There's a Dutch scouting tradition called "dropping." Kids get driven to an unfamiliar forest at night - sometimes blindfolded - and have to find their way back to camp. It builds independence, problem-solving, resilience.
That's what most people do to their AI agents.
Drop them in a codebase. No orientation. Figure it out. (Veel succes en heel gezellig, as the Dutch would say.)
The difference is that, unlike people, the AI Agent memory goes as far as context allows.
find . -name "*.yml" -type f
grep -r "config" --include="*.md"
ls -la .claude/
The agent explores. Makes wrong assumptions. Gets corrected. Tries again. Eventually finds what it needs, or doesn't and quietly poison context.
I call this the exploration tax - the tokens and time spent orienting instead of working.
Give the agent a map
The fix is simple: one file that maps your project.
# backbone.yml
version: 1
structure:
config: config/
src: src/
tests: tests/
docs: docs/
conventions:
test_pattern: "*.test.ts"
config_format: yaml
boundaries:
never_modify:
- .env
- migrations/
- vendor/
That's enough to start. Claude reads this once and knows: config lives in config/, tests are *.test.ts, never touch .env or migrations/.
No more exploration loops. No more wrong guesses. No more "sorry, I thought the config was in the root directory."
Scaling up
As your project grows, so can your backbone. Here's what mine looks like for Reporails rules:
version: 3
agents:
claude:
main_instruction_file: CLAUDE.md
config: agents/claude/config.yml
skills: .claude/skills/
tasks: .claude/tasks/
codex:
config: agents/codex/config.yml
rules:
core: core/
agents: agents/
patterns:
rule_dir: "{category}/{slug}/"
definition: "rule.md"
test_pass: "tests/pass/"
test_fail: "tests/fail/"
categories:
structure: core/structure/
content: core/content/
efficiency: core/efficiency/
maintenance: core/maintenance/
schemas:
rule: schemas/rule.schema.yml
capability: schemas/capability.schema.yml
agent: schemas/agent.schema.yml
registry:
capabilities: registry/capabilities.yml
levels: registry/levels.yml
coordinate_map: registry/coordinate-map.yml
Multiple agents, rule patterns, schemas, registries - all mapped. Claude can construct paths directly instead of exploring.
Wiring it up
The backbone file alone isn't enough - you need to tell Claude to use it. Add this to your CLAUDE.md:
## Initialization
Read these files before searching or modifying anything:
1. Read `backbone.yml` for project structure and path resolution
2. Read any registries or schemas referenced there as needed
3. Read `.claude/rules/` for context-specific constraints
## Structure
Defined in `backbone.yml` - the single source of truth for project topology.
**BEFORE** running `find`, `grep`, `ls`, or glob to locate project files, read `backbone.yml` first. All paths are mapped there. Do not use exploratory commands to discover paths that the backbone already provides.
This is the key: explicit instruction to read the map before exploring. Without it, Claude might still wander.
Why a separate file?
You could put all of this directly in your CLAUDE.md. But there's a tradeoff.
Everything in CLAUDE.md sits in the context window from the start - every session, every message, whether the agent needs it or not.
backbone.yml is read-on-demand. Claude doesn't load it at session start - it reads it when it would otherwise start exploring. The map replaces discovery, not adds to it.
There are also things a directory structure can't express:
-
Patterns.
{category}/{slug}/rule.mdisn't a folder - it's a convention. - Relationships. Which agent owns which config? What schema validates what file?
- Boundaries. What's off-limits? What's deprecated?
Directories show what exists. backbone.yml shows how it fits together.
The cost of exploration
I tracked my Claude Code usage across 176 sessions. A significant chunk of friction came from wrong assumptions about project structure:
- Used the wrong YAML library (PyYAML instead of ruamel.yaml)
- Wrote changes to the wrong repo in a monorepo
- Assumed directories existed that didn't
- Missed config files that were right there
Each mistake costs tokens, time, and trust. The models are smart enough - the problem is orientation.
Where this fits
In my previous post, I introduced capability levels for instruction files:
- L1-L2: CLAUDE.md exists, has basic constraints
- L3: External references, multiple files
- L4: Path-scoped rules that load conditionally
- L5: backbone.yml - maintained structure, active upkeep
- L6: Dynamic context, skills, MCP integration
Most setups stop at L2-3. The jump to L5 isn't about adding more rules - it's about making your existing setup navigable. backbone.yml is how you get there.
When to adopt this
Not every project needs it. Weekend hack? Basic CLAUDE.md is fine.
But if you notice:
- Claude repeatedly exploring the same directories
- Wrong assumptions about project structure
- Corrections like "no, the config is in X, not Y"
- Monorepo confusion about which repo to modify
...you're paying the exploration tax. A backbone file pays for itself in the first session.
Keep it accurate
A backbone.yml only works if it's true. Paths that don't resolve, patterns that don't match reality - those are worse than no map at all.
Structure that rots is worse than no structure.
Try it
- Create
backbone.ymlin your project root - Map your directories, configs, conventions
- Add the initialization section to your CLAUDE.md
- Watch Claude stop guessing
I use this with Claude Code daily. The pattern should work for any agent that reads instruction files - Codex, Copilot, Cursor - though I haven't tested all of them. If you try it, let me know how it goes.
Don't drop your agent in the dark. Give it a map.
Reporails is where I'm building instruction file governance. The backbone.yml example above is from there.
Top comments (0)