A few months with Claude Code: tips and workflows that helped me

Overview

Agentic AI Series β€” Part 2

This article follows Agentic Coding: concepts and hands-on use cases, where we explored the fundamentals of agentic AI β€” tokens, MCPs, Skills, Tasks β€” and two detailed practical examples. Here, we dive into advanced practices: how to get the most out of Claude Code on a daily basis.

As with any tool you adopt, it takes time to refine how you use it. After iterating on my config and workflows, I've found an efficient rhythm with Claude Code. Here's what works for me.

Living article

This article will be updated as I discover new things and as tools evolve. Feel free to check back from time to time for new tips.


📜 CLAUDE.md: persistent memory

The CLAUDE.md file is the first optimization lever. These are instructions automatically injected into every conversation. If you don't have one yet, it's the first thing to set up.

Loading hierarchy

Claude Code loads CLAUDE.md files according to a specific hierarchy:

LocationScopeUse case
~/.claude/CLAUDE.mdAll sessions, all projectsGlobal preferences (language, commit style)
./CLAUDE.mdProject (shared via git)Team conventions, build/test commands
./CLAUDE.local.mdProject (not versioned)Personal preferences on this project
./subfolder/CLAUDE.mdSubtreeInstructions specific to a module

Files are cumulative: Claude loads all of them from most global to most local. In case of conflict, the most local one wins.

What I put in mine

Here's what the CLAUDE.md for cloud-native-ref actually contains:

  • Build/test/lint commands β€” the first lines, so Claude knows how to validate its work
  • Project conventions β€” xplane-* prefix for IAM, Crossplane composition structure, KCL patterns
  • Architecture summary β€” key folder structure, not a novel
  • Common pitfalls β€” traps Claude keeps falling into if you don't warn it (e.g., wrong default namespace, label format)

What I don't put in it: exhaustive documentation (that's what Skills are for), long code examples (I reference existing files instead), and obvious instructions Claude already knows.

Here's a condensed excerpt from the CLAUDE.md of cloud-native-ref to illustrate:

 1## Common Commands
 2
 3### Terramate Operations
 4# Deploy entire platform
 5terramate script run deploy
 6# Preview changes across all stacks
 7terramate script run preview
 8# Check for configuration drift
 9terramate script run drift detect
10
11## Crossplane Resources
12- **Resource naming**: All Crossplane-managed resources prefixed with `xplane-`
13
14## KCL Formatting Rules
15**CRITICAL**: Always run `kcl fmt` before committing KCL code. The CI enforces strict formatting.
16
17### Avoid Mutation Pattern (Issue #285)
18Mutating dictionaries after creation causes function-kcl to create duplicate resources.
19   # ❌ WRONG - Mutation causes DUPLICATES
20   _deployment = { ... }
21   _deployment.metadata.annotations["key"] = "value"  # MUTATION!
22
23   # βœ… CORRECT - Use inline conditionals
24   _deployment = {
25       metadata.annotations = {
26           if _ready:
27               "krm.kcl.dev/ready" = "True"
28       }
29   }

You'll find the three essential ingredients: build/deploy commands first (so Claude knows how to validate its work), naming conventions, and specific pitfalls Claude would keep reproducing if not warned.

The ~500-line rule

Every token in CLAUDE.md is loaded in every conversation. An overly long file wastes precious context. Aim for ~500 lines maximum and move specialized instructions to Skills that only load on demand.

Iterating on CLAUDE.md

Treat CLAUDE.md as a production prompt: iterate on it regularly. The # shortcut lets you ask Claude itself to suggest improvements to your file. You can also use Anthropic's prompt improver to refine the instructions.


🪝 Hooks: my first automation

Hooks are shell commands that run automatically in response to Claude Code events. The key difference with CLAUDE.md: CLAUDE.md instructions are advisory (Claude can ignore them), hooks are deterministic β€” they always run.

Getting notified when Claude is waiting

The first hook I set up β€” and the one I recommend to everyone β€” is the desktop notification. When Claude finishes a task or is waiting for your input, you get a system notification with a sound. No more checking the terminal every 30 seconds.

Configuration in ~/.claude/settings.json:

 1{
 2  "hooks": {
 3    "Notification": [
 4      {
 5        "matcher": "",
 6        "hooks": [
 7          {
 8            "type": "command",
 9            "command": "notify-send 'Claude Code' \"$CLAUDE_NOTIFICATION\" --icon=dialog-information && paplay /usr/share/sounds/freedesktop/stereo/complete.oga"
10          }
11        ]
12      }
13    ]
14  }
15}

On Linux, notify-send is provided by the libnotify package and paplay by pulseaudio-utils (or pipewire-pulse). Other mechanisms exist for macOS (osascript) or other environments β€” see the hooks documentation for alternatives.

Other possibilities

Hooks cover several events (PreToolUse, PostToolUse, Notification, Stop, SessionStart) and enable things like:

  • Auto-format after each edit (e.g., gofmt on Go files)
  • Sensitive file protection β€” a PreToolUse hook that blocks writes to .env, .pem, .key files (exit code 2 = action blocked)
  • Audit of executed commands in a log file

I won't detail every variant here β€” the official hooks documentation does a great job. The key takeaway is that hooks are your deterministic safety net where CLAUDE.md is merely advice.


🧠 Mastering the context window

The context window (200K tokens) is the most critical resource. Once saturated, old information gets compressed and quality degrades. This is THE topic that makes the difference between an efficient user and someone who "loses" Claude after 20 minutes.

/compact with custom instructions

The /compact command compresses conversation history while preserving key decisions. The trick: you can pass focus instructions to keep what matters:

1/compact focus on the Crossplane composition decisions and ignore the debugging steps

This is especially useful after a long debugging session where 80% of the context is noise (failed attempts, stack traces).

/clear strategy

The /clear command resets the context to zero. When to use it?

  • Always between two distinct tasks β€” this is the most important rule
  • When Claude starts hallucinating or repeating mistakes
  • After a long debugging session (context is polluted with failed attempts)
  • When /context shows < 20% free space

I've made a habit of starting every new task with a /clear. It seems counterintuitive (you lose context), but in practice it's much more effective than a polluted context.

Tool Search: when MCPs eat your context

The problem: each enabled MCP injects its tool definitions into the context. With 6-7 configured MCPs (common in platform engineering), that can represent over 10% of your window β€” consumed before you even start working.

The solution: enable Tool Search:

1export ENABLE_TOOL_SEARCH=auto:10

With this option, Claude only loads tool definitions when it needs them, rather than keeping them all in memory. The 10 is the threshold (as a percentage of context) at which the mechanism kicks in.

Delegating to subagents

For large exploration tasks (browsing a codebase, searching through logs), Claude can delegate to subagents that have their own isolated context. The condensed result is sent back to the main session β€” saving precious tokens.

In practice, Claude does this automatically when it deems it relevant (file exploration, broad searches). But you can also guide it explicitly: "use a subagent to explore the networking module structure".

A few simple rules

  1. /clear between tasks: Each new task should start with a /clear
  2. Keep CLAUDE.md concise: Every token is loaded in every conversation
  3. CLIs > MCPs: For mature tools (kubectl, git, gh...), prefer the CLI directly β€” LLMs know them perfectly and it avoids loading an MCP
  4. /context to audit: Identify what's consuming context and disable unused MCPs

🔄 Multi-session workflows

Git Worktrees: parallelizing sessions

Rather than juggling branches and stash, I use git worktrees to work on multiple features in parallel with independent Claude sessions.

1# Create two features in parallel
2git worktree add ../worktrees/feature-a -b feat/feature-a
3git worktree add ../worktrees/feature-b -b feat/feature-b
4
5# Launch two separate Claude sessions
6cd ../worktrees/feature-a && claude  # Terminal 1
7cd ../worktrees/feature-b && claude  # Terminal 2

Each session has its own context and its own memory β€” no interference between tasks.

Worktree vs repo copy

Unlike a separate git clone:

  • Shared history: A single .git, commits are immediately visible everywhere
  • Disk space: ~90% savings (no git object duplication)
  • Synchronized branches: git fetch in one worktree updates all others

When the change is done (PR merged), just go back to the main repo and clean up.

1cd <path_to_main_repo>
2git worktree remove ../worktrees/feature-a
3git branch -d feat/feature-a  # after PR merge

Useful commands:

1git worktree list              # See all active worktrees
2git worktree prune             # Clean up orphaned references

Writer/Reviewer pattern

A pattern I use more and more involves running two sessions in parallel:

SessionRolePrompt
WriterImplements the code"Implement feature X according to the spec"
ReviewerReviews the code"Review the changes on the feat/X branch, check security and edge cases"

The reviewer works on the same repo (via worktree or read-only) and provides independent feedback, without the author's bias. This is especially effective for infrastructure changes where a mistake can be costly.

Fan-out with -p

The -p flag (non-interactive prompt) lets you run Claude in headless mode and parallelize tasks:

1# Launch 3 tasks in parallel
2claude -p "Add unit tests for the auth module" &
3claude -p "Document the REST API for the orders service" &
4claude -p "Refactor the billing module to use the new SDK" &
5wait

Each instance has its own context. This is ideal for independent tasks that don't require interaction.


🖥️ Hybrid IDE + Claude Code workflow

In practice, I alternate between two modes: sometimes pure terminal β€” old habits β€” and sometimes hybrid with Cursor for editing and Claude Code in the terminal. The hybrid workflow is clearly more comfortable, and I'm moving towards it more and more.

Cursor + Claude Code
NeedToolWhy
Quick editing, autocompleteCursorMinimal latency, you stay in the flow
Refactoring, multi-file debuggingClaude CodeDeep reasoning, autonomous loops

What I like about hybrid mode: Claude makes changes via the terminal, and I review the diffs in the Cursor interface β€” much more readable than git diff. Changes appear in real time in the editor, which lets you follow what Claude is doing and step in quickly if needed.


🔌 Plugins

Claude Code has a plugin ecosystem that extends its capabilities. Here are the two I use daily:

Code-Simplifier: cleaning up generated code

The code-simplifier plugin is developed by Anthropic and used internally by the Claude Code team. It automatically cleans up AI-generated code while preserving functionality.

I discovered this plugin recently and intend to make a habit of using it before creating a PR after an intensive session. It runs on Opus and should help reduce the technical debt introduced by AI code β€” duplicated code, unnecessarily complex structures, inconsistent style.

Claude-Mem: persistent memory across sessions

The claude-mem plugin automatically captures your session context and reinjects it in future sessions. No more re-explaining your project at the start of every conversation.

Its two main strengths:

  • Semantic search: easily find information from a past session via the mem-search skill
  • Token consumption optimization: a 3-layer workflow that significantly reduces usage (~10x savings)

Usage examples:

  • "Search my sessions for when I debugged Karpenter"
  • "Find what I learned about OpenBao PKI last week"
  • "Look at my previous work on the App composition"
Privacy considerations

Claude-mem stores session data locally. For sensitive projects, use <private> tags to exclude information from capture.


⚠️ Anti-patterns

Here are the traps I fell into β€” and learned to avoid:

Anti-patternSymptomSolution
Kitchen sink sessionMixing debugging, features, refactoring in the same session/clear between each distinct task
Correction spiralClaude fixes a bug, creates another, loops endlesslyStop, /clear, rephrase with more context
Bloated CLAUDE.mdContext consumed from the start, degraded responsesTarget ~500 lines, move the rest to Skills
Trust-then-verify gapAccepting code without review, finding bugs in prodAlways read the diff before committing
Infinite explorationClaude browses the entire codebase instead of actingGive specific files/paths in the prompt
The most insidious trap

The correction spiral is by far the most dangerous. A real example: Claude was supposed to add a CiliumNetworkPolicy to a Crossplane composition. First attempt, wrong endpoint selector. It fixes it, but breaks the KCL format. It fixes the format, but reverts to the original bad selector. After 5 iterations and ~40K tokens consumed, I hit /clear and rephrased in 3 lines, specifying the target namespace and an example of an existing policy. Correct result on the first try. The lesson: when Claude loops after 2-3 attempts, it's a sign it's missing context, not persistence. Better to cut and rephrase than to let it spin.


🏁 Conclusion

Over time, I've become increasingly comfortable with Claude Code, and the productivity gains are real. But they come with a lingering concern I can't fully shake: losing control β€” over the produced code, over the decisions made, over the understanding of what's running in production.

These questions, as well as the methods that help me stay in control, are covered in the first article of this series. If you want to revisit the fundamentals or understand where these reflections come from, I highly recommend it: Agentic Coding: concepts and hands-on use cases.


🔖 References

Official documentation

Community guides

Plugins and tools

Previous article

Translations: