As a backend engineer, I spend most of my time inside microservice architectures. And if you've worked in this world, you know the point: you're deep into one service and suddenly you need to understand how your changes ripple across the system. Which services consume this event? What breaks downstream if I change this contract?
When everything lives in a single repository, Claude Code handles this beautifully — you drop a CLAUDE.md file at the root and it has all the context it needs.
But microservices live in separate repos. That's where things get interesting.
The setup
The idea starts with a parent folder containing all your microservice repositories:
platform/
├── CLAUDE.md ← high-level system overview
├── user-service/
│ └── CLAUDE.md ← service-specific context
├── order-service/
│ └── CLAUDE.md ← service-specific context
├── notification-service/
│ └── CLAUDE.md ← service-specific context
└── ...
Each microservice keeps its own CLAUDE.md — minimal, focused: what the service does, its API surface, key domain concepts, tech stack specifics. On the other hand, the root-level CLAUDE.md describes the system as a whole: how services interact, which events flow where, shared conventions, the big architectural picture.
This layered structure enables two distinct ways of working with Claude Code, depending on where you launch it from.
Working inside a single service
When you cd into a service directory and run Claude Code, it automatically picks up the parent CLAUDE.md in addition to the service's own file. Claude immediately knows your service doesn't exist in isolation — it understands the neighbors, the contracts, the event flows. You're fixing a bug in one service and Claude can already warn you: "the notification-service subscribes to this event — your change might break that contract."
Designing cross-service features
Sometimes you need to zoom out. That's when you run Claude from the root folder:
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 claude --add-dir $(ls -d */)
The --add-dir flag grants Claude Code read access to additional directories beyond the one you launched it from. The $(ls -d */) part expands to all subdirectories — every microservice repo in your workspace — so Claude can navigate into any service, read the code, and reason about it.
The environment variable CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD completes the picture. By default, --add-dir only gives file access — it doesn't load the CLAUDE.md files from those directories into context. Setting it to 1 changes that: Claude picks up every service's CLAUDE.md, giving it the full architectural map. You're pair-programming at the system level.
What I learned
Keep the service-level CLAUDE.md files lean — think "elevator pitch," not architecture decision records. The root file is the glue: relationships, flows, shared language that no single service owns.
This isn't a silver bullet — you still need to keep those files up to date, and there's a balance with context window size. But as a pattern, it's been a significant upgrade. The setup takes minutes. The payoff is immediate.
Top comments (0)