Strukturierung von Claude Code-Projekten, damit Agenten in großen Repositorien fokussiert bleiben
Sechs Muster für große Codebasen: schichtweise CLAUDE.md-Dateien, Fähigkeiten, Subagenten, Ablehnungsregeln, spärliche Worktrees sowie Language-Server-Plugins, die den Kontext des Agents sauber halten.
Quellen: How I Structure Claude Code Projects So Agents Don’t Get Lost in Large Codebases
Stellen Sie sich eine einfache Anfrage an Claude Code vor: Beheben Sie einen Fehler wegen Zeitüberschreitung bei Sitzungen im Authentifizierungs-Middleware. Die eigentliche Lösung besteht aus nur drei Zeilen. Doch bevor der Agent dorthin gelangt, durchforstet er das Protokollierungssystem, die Migrationsgeschichte, die Hälfte der API-Endpunkte und aus Gründen, die niemand erklären kann, auch die Terraform-Konfigurationen. Nachdem der Agent bereits das 147. Datei gelesen hat, gibt der Entwickler auf.
In einer solchen Situation ist das Modell nicht der Schuldige – vielmehr liegt das Problem im Projektlayout. Jede Konvention, jeder Build-Befehl und jede architektonische Entscheidung war in ein einziges 340 Zeilen umfassendes CLAUDE.md zusammengefasst worden, das der Agent beim Starten gewissenhaft durchlas, bevor er den Rest seiner Ressourcen damit verbrachte, Code zu untersuchen, der nichts mit der Authentifizierung zu tun hatte.
Das ist das Ergebnis, wenn ein Agent wie ein Neuzugang behandelt wird, der das gesamte Firmenhandbuch durchlesen muss, bevor er einen Tippfehler korrigieren kann. Er benötigt den richtigen Kontext zum richtigen Zeitpunkt – und nicht alles auf einmal. Es folgen sechs Muster, die dieses Problem lösen, zusammen mit einer Methode, um zu beurteilen, wann jedes davon sinnvoll ist.
Warum der Kontext schnell aufgebraucht wird
Das Kontextfenster von Claude Code, etwa 200.000 Token beim hier verwendeten Modell, klingt enorm – bis man aufzählt, was dagegen zählt: jede gesendete Nachricht, jede gelesene Datei, alle Ausgaben von Befehlen, jede CLAUDE.md-Anweisung sowie alle automatisch gespeicherten Notizen im Gedächtnis. Ein Token entspricht in etwa vier Zeichen.
In einer großen Codebasis können bereits 50.000 Tokens verschwinden, bevor eine einzige Codezeile geschrieben wird. Ein 300 Zeilen langes Root-Datei CLAUDE.md kostet etwa 1.200 Tokens, eine 500 Zeilen lange Datei weitere 2.000 Tokens, und das Durchsuchen mit grep oder find fügt noch mehr hinzu. Bis der Agent die Aufgabe versteht, kann bereits die Hälfte der verfügbaren Zeit vorbei sein. Wenn die Zeit wieder zunimmt, sinkt die Leistung: Frühere Anweisungen werden vergessen, Dateien müssen erneut gelesen werden, und es treten Fehler auf, die bei einem sauberen Kontext nicht auftreten würden. Größere Zeitfenster sind daher keine Lösung – entscheidend ist es, irrelevante Inhalte aus dem Zeitfenster herauszuhalten.
Muster 1: schichtweise CLAUDE.md-Dateien
Der erste Fehler besteht darin, alles in die Root-Datei zu packen: Build-Befehle für die API, Muster für Frontend-Komponenten, Migrationen, Deploy-Checklisten sowie Testkonventionen zusammen.
Claude Code liest bei Start einer Sitzung die CLAUDE.md-Dateien aus dem Arbeitsverzeichnis bis zum Wurzelverzeichnis des Repositoriums. Wenn man es in einem Unterverzeichnis startet, nimmt es die Dateien dieses Verzeichnisses sowie alle übergeordneten Verzeichnisse bis zur Wurzel in Betracht. Teilen Sie daher den Inhalt nach Scope auf:
monorepo/
CLAUDE.md # repository-wide rules only
packages/
api/
CLAUDE.md # API-specific conventions
.claude/skills/
src/
web/
CLAUDE.md # frontend-specific conventions
.claude/skills/
src/
shared/
CLAUDE.md # shared library conventions
src/
Die Wurzeldatei enthält lediglich die Struktur des Repositoriums sowie die Konventionen für Commit-Vorgänge – etwa 40 Zeilen – und jedes Paket weist seine eigenen, stack-spezifischen Details auf. Starten Sie den Agenten in packages/api/, und er lädt die Wurzeldatei sowie die API-Datei, ohne jemals auf die Konventionen des Frontends zuzugreifen. Wechseln Sie zu packages/web/, und dieselbe Logik liefert einen anderen Kontextabschnitt.
Eine Wurzeldatei könnte wie folgt aussehen:
# Repository Structure
This is a monorepo with three packages under packages/:
- packages/api: Node.js REST API with Express, TypeScript, PostgreSQL
- packages/web: React frontend with Vite, TypeScript, TailwindCSS
- packages/shared: shared TypeScript utilities
Run commands from the package directory, not the monorepo root.
Each package has its own tsconfig.json, package.json, and test suite.
# Commit Conventions
- Prefix commits with the package name: "api: fix session timeout"
- One commit per logical change
- Run tests before committing
Und das API-Paket enthält nur das, was innerhalb dieses Pakets wichtig ist:
# API Package
This is the REST API server.
## Commands
- Run tests: `npm test` (uses Vitest)
- Run dev server: `npm run dev` (port 3001)
- Database migrations: `npm run migrate`
- Environment variables: copy `.env.example` to `.env`
## Code Patterns
API routes are in src/routes/. Each route file exports an Express router.
Database queries use Knex in src/db/. Never write raw SQL in route handlers.
## Testing
Tests are in src/__tests__/ mirroring the src/ directory.
Use supertest for HTTP assertions, not raw fetch.
Always wrap database tests in a transaction that rolls back.
In diesem Beispiel beträgt die Anzahl der geladenen Kontextzeilen 80 anstelle von 340, und die Authentifizierungsbehebung beinhaltet 12 Dateien statt 147.
Muster 2: Fähigkeiten für Wissen auf Abruf
Auch eine schichtweise Struktur kann überdimensioniert sein. Testmuster, Bereitstellungs-Checklisten und Debugging-Anleitungen sind Verfahren und keine Fakten – der Agent benötigt sie nicht beim Start, sondern nur dann, wenn die Aufgabe sie erfordert. Dafür sind Fähigkeiten zuständig.
Fähigkeiten befinden sich unter .claude/skills/ und werden geladen, wenn Claude sie für relevant hält oder wenn sie explizit über einen Slash-Befehl aufgerufen werden. Die Beschreibung einer Fähigkeit gibt an, wann sie verwendet werden soll, und ihr Inhalt enthält den eigentlichen Inhalt. Hier werden die Testanleitungen aus der API-Datei in eine Fähigkeit verlegt:
# .claude/skills/api-testing/SKILL.md
---
name: api-testing
description: Testing patterns for the API package. Use when writing or modifying tests in packages/api/.
---
## Test Structure
Tests are in `src/__tests__/` mirroring the `src/` directory structure.
Each route file has a corresponding `.test.ts` file.
## Running Tests
- All tests: `npm test`
- Single file: `npm test -- src/__tests__/routes/users.test.ts`
- Watch mode: `npm test -- --watch`
## Test Utilities
- `src/__tests__/helpers/db.ts`: provides `setupTestDb()` and `teardownTestDb()`
- `src/__tests__/helpers/auth.ts`: provides `createTestUser()` and `getAuthToken()`
## Patterns
- Use `supertest` for HTTP assertions, not raw fetch
- Always wrap database tests in a transaction that rolls back
- Mock external services in `src/__tests__/mocks/`
Bitten Sie um Tests am Auth-Middleware, wobei der Agent die Testfähigkeit lädt und deren Muster befolgt. Bitten Sie ihn, den Timeout-Bug zu beheben – die Fähigkeit bleibt jedoch ungeladen, da Tests nicht relevant sind.
Fähigkeiten eignen sich auch für wiederholbare Workflows. Eine mit /fix-pr-comments aufgerufene Fähigkeit könnte Bewertungskommentare zu einem GitHub-Pull-Request lesen, die gewünschten Änderungen ermitteln, den Code bearbeiten, Tests ausführen und die Änderungen hochladen. Der gesamte Ablauf befindet sich in der Fähigkeit und nicht in einem CLAUDE.md, das bei jeder Sitzung Kontext verbraucht.
Die Faustregel lautet: Fakten, die bei jeder Sitzung benötigt werden, gehen in CLAUDE.md, während Verfahren und Referenzmaterialien zu Fähigkeiten werden.
Muster 3: Subagenten für isolierte Erkundungen
Auch mit Schichten und Fähigkeiten wirkt die Erkundung zu aufwendig. Die Frage „Wie funktioniert die Authentifizierung?“ kann dazu führen, dass 40 Dateien gelesen werden, da der Agent den Anmeldevorgang, die Sitzungsspeicherung, den Token-Refresh und das Abmelden nachvollzieht – und all dieser Text bleibt nach Beantwortung der Frage im Hauptgespräch erhalten und verschmutzt den Rest der Sitzung.
Ein Unteragent läuft in seinem eigenen Kontextfenster, führt die Erkundung durch und sendet nur eine Zusammenfassung zurück. Die gelesenen Dateien sowie die Ausgaben von grep bleiben in seinem Kontext. Der Hauptthread erhält lediglich die Zusammenfassung, wodurch er sauber bleibt. Eine Forschungsanfrage könnte wie folgt aussehen:
Use a subagent to investigate how our authentication system handles
session timeout and token refresh. Report back what files are involved
and how the flow works.
Der Unteragent liest alles, was benötigt wird, verfolgt den Ablauf und berichtet zurück, sodass das Hauptgespräch eine klare Erklärung von etwa 200 Wörtern erhält und nicht den Inhalt von 40 Dateien. Unteragenten helfen außerdem bei der Überprüfung nach einer Implementierung:
Use a subagent to review the session timeout fix for edge cases
and consistency with our existing auth patterns.
Der prüfende Unteragent sieht den Diff in seinem aktuellen Zustand, ohne die Begründung, die die Änderung verursacht hat.
Eine Vorsichtsmaßnahme: Zusammenfassungen gehen auf Details ein. Wenn Sie genaue Zeilennummern oder Codeausschnitte benötigen, muss der Hauptagent möglicherweise die Dateien erneut lesen, die der Unteragent bereits gesehen hat. Während die Erkundung an anderer Stelle stattfindet, konzentriert sich der Unteragent auf die Umsetzung des Hauptziels.
Muster 4: Generierte und übernommene Dateien ungelesen lassen
Alles, was in .gitignore aufgeführt ist, wird standardmäßig übersprungen, wodurch node_modules/, dist/ und build/ aus den Suchergebnissen ausgeschlossen bleiben. Einige generierte oder übernommene Codeabschnitte werden dennoch gespeichert: kompilierte protobuf-Definitionen, übernommene SDKs sowie generierte GraphQL-Typen. Der Agent wird diese gerne öffnen, falls sie bei einer Suche auftauchen – obwohl das eigentlich nie der Fall sein sollte.
Die Regeln zur Ablehnung von Berechtigungen verhindern das Lesen der ausgewählten Dateimuster. Die allgemeine Struktur ist unten dargestellt, und die genaue Syntax sollte in der Dokumentation für Ihre Claude Code-Version überprüft werden:
# packages/api/.claude/settings.json
{
"permissions": {
"deny": [
"Read(./**/dist/**)",
"Read(./**/build/**)",
"Read(./**/*.generated.*)",
"Read(./vendor/**)"
]
}
}
Wenn eine Suche nach „GraphQL resolvers“ nun eine generierte Schema-Datei findet, wird das Ergebnis angezeigt, doch das Lesetool antwortet mit „Erlaubnis verweigert“, und der Agent fragt in der Regel nach dem eigentlichen Quellcode. Ein Nebeneffekt, den man kennen sollte: Dasselbe Regelwerk verhindert auch manuell durchgeführte Lesevorgänge im Chatfenster. Wenn man es bittet, src/schema.generated.ts zu öffnen, wird dies abgelehnt – entfernen Sie die Regel vorübergehend. Der Vorteil ist, dass generierter „Rauschen“ außerhalb des Kontexts bleibt und der Agent auf den echten Quellcode gelenkt wird.
Muster 5: spärliche Worktrees
Claude Code kann git Worktrees für parallele oder isolierte Arbeiten erstellen, wobei standardmäßig jeder Worktree das gesamte Repository herunterlädt. In einem Monorepo ist das verschwenderisch, da eine API-Änderung nicht den Frontend-Code benötigt.
Git’s sparse-checkout schreibt nur ausgewählte Verzeichnisse auf die Festplatte und lässt den Rest im Index, wobei die Einstellung worktree.sparsePaths darauf aufbaut. Überprüfen Sie den Konfigurations Schlüssel anhand der Dokumentation für Ihre Version:
# packages/api/.claude/settings.json
{
"worktree": {
"sparsePaths": [
".claude",
"packages/api",
"packages/shared"
]
}
}
Worktrees enthalten dann nur .claude/, packages/api/ und packages/shared/ sowie Dateien wie package.json und tsconfig.base.json. Sie lassen sich schneller erstellen und nehmen weniger Speicherplatz ein. Wenn der Agent versucht, eine nicht ausgecheckte Datei zu lesen, wirft git einen Fehler aus, und der Agent fragt in der Regel nach den vorhandenen Verzeichnissen. Sparse-checkout erfordert git 2.25 oder neuer, was git --version bestätigen wird.
Muster 6: Code-Intelligenz anstelle von Dateisuche
Um herauszufinden, wo eine Funktion in einer großen Codebasis definiert oder verwendet wird, sind viele grep-Aufrufe und Datei-Lesungen erforderlich, da der Agent die Ergebnisse durchsucht, mögliche Kandidaten öffnet und weiter sucht.
Code-Intelligenz-Plugins verbinden den Agenten mit einem Sprachserver. Anstelle eines Scannens fragt er nach, wo refreshAuthToken definiert ist, und erhält sofort eine Datei sowie die Zeilennummer. Für TypeScript-Projekte wird das offizielle LSP-Plugin auf diese Weise installiert, wobei die Installationssyntax je nach Version variiert – prüfen Sie daher die Dokumentation:
/plugin install typescript-lsp@claude-plugins-official
Fragen Sie nach dem Ort, an dem refreshAuthToken verwendet wird, und der Agent fragt den Sprachserver ab und erhält als Antwort:
src/middleware/auth.ts:47
src/routes/users.ts:103
src/__tests__/auth.test.ts:22
Es waren keine Dateiabrufe erforderlich, wodurch die Antworten schneller geliefert werden und der Kontext sauber bleibt. Der Plugin meldet außerdem Typfehler nach Änderungen, ohne tsc ausführen zu müssen, sodass Fehler sofort sichtbar werden. Er ergänzt sich gut mit Ablehnungsregeln: Diese blockieren Störungen, während die Code-Intelligenz die Notwendigkeit, den verbleibenden Code zu durchscannen, verringert.
Alle sechs zusammen
Bei Anwendung jedes Musters verläuft die ursprüngliche Fehlerbehebung in etwa wie folgt:
- Starten Sie Claude von
packages/api/aus. - Es lädt das Root-Datei
CLAUDE.md(40 Zeilen) sowie die API-Datei (50 Zeilen) hoch. - Sie bitten es, den Fehler des Sitzungstimers im Auth-Middleware zu beheben.
- Es schickt einen Subagenten, um den Auth-Flow zu untersuchen, der in seinem eigenen Kontext etwa 20 Dateien liest.
- Der Subagent berichtet, dass die Timeout-Logik sich in
src/middleware/auth.tsauf Zeile 47 befindet und einen falschen Vergleichsoperator verwendet. - Der Hauptentwickler liest diese Datei, behebt den Fehler, schreibt einen Test und führt ihn aus, wobei etwa vier Dateien im Hauptkontext verändert werden.
In dieser Darstellung sehen die Werte vor und nach der Umsetzung wie 147 Datei-Lesungen, drei fehlgeschlagene Versuche und 35 Minuten im Vergleich zu etwa vier Lesungen, einem erfolgreichen Versuch und 6 Minuten aus. Betrachten Sie dies als Anekdote eines Entwicklers und nicht als Benchmark – doch die Richtung ist entscheidend: Die Struktur beseitigte die Hindernisse zwischen Frage und Antwort.
Die Auswahl dessen, was Sie benötigen
Nicht jedes Projekt benötigt alle sechs Elemente. Ein einzelnes Repository mit 50 Dateien braucht weder schichtweise strukturierte Dateien noch spärliche Arbeitsbäume. Sobald die Codebasis größer wird, als eine Person im Kopf behalten kann, zeigen diese Strukturen ihre Vorteile:
- Layered
CLAUDE.mdFiles eignen sich, wenn Sie bei der Scrollung durch unwichtige Abschnitte in der Root-Datei weiterblättern oder wenn Teamkollegen fragen, warum die API-Datei Frontend-Regeln enthält. - Skills eignen sich, wenn ein Abschnitt von
CLAUDE.mdzu einem Verfahren oder Checkliste geworden ist oder Sie immer wieder dieselben Anweisungen in den Chat kopieren. - Subagents eignen sich, wenn eine Untersuchung damit endet, dass „lesen Sie diese 30 Dateien“ angegeben wird, oder wenn Sie eine unvoreingenommene Überprüfung wünschen.
- Deny Rules eignen sich, wenn der Agent trotz von
.gitignoregenerierten oder übernommenen Codes weiterhin darauf zugreift. - Sparse Worktrees eignen sich, wenn es für ein Monorepo länger als 10 Sekunden dauert, es auszuchecken, oder wenn Sie viele Worktrees parallel erstellen.
Das Ziel ist es nicht, alles blind anzuwenden. Es geht darum, zu erkennen, wann der Kontext überladen wird, und das passende Muster auszuwählen, um ihn zu bereinigen. Andere Strukturen können auch für große Codebasen funktionieren, doch diese sechs machen aus einem Agenten, der alles liest, einen Agenten, der nur die richtigen Dateien liest, die Korrektur vornimmt und dann aufhört.