Getting productive fast in a large, grown codebase
Claude Code only becomes genuinely useful once it understands the conventions of an existing project, instead of guessing anew with every request. A carefully written CLAUDE.md, a deliberately limited context window, and clear exclusion rules for vendor and generated directories decide whether Claude Code becomes productive quickly in a large PHP or Magento codebase or keeps making wrong assumptions.
Table of Contents
- 1. Why onboarding works differently in existing projects
- 2. The first 30 minutes: starting Claude Code in an existing project
- 3. Writing an effective CLAUDE.md
- 4. Making project conventions and forbidden patterns explicit
- 5. Protecting the context window: what must be excluded
- 6. Practical example: onboarding a Magento 2 project
- 7. Refining CLAUDE.md iteratively instead of writing it once
- 8. Security and permissions in existing projects
- 9. Onboarding practice compared side by side
- 10. Summary
- 11. FAQ
1. Why onboarding works differently in existing projects
Claude Code doesn't read project documentation in the classic sense, it reads the code itself, supplemented by the CLAUDE.md file as project-specific context. In a new, empty project that's unproblematic: there's barely any legacy baggage, and conventions form together with the model as work progresses. In a grown Magento store with several years of history, multiple developer teams, and thousands of files including vendor/ and generated/, the starting point looks completely different. The context window is finite, and unfiltered code pulled in from different eras of the project causes Claude Code to treat contradictory patterns as equally valid.
The key difference from a new project: in an existing codebase, multiple solutions to the same problem often coexist because standards changed over time. An old module might still use Preferences instead of Plugins, while a newer module already uses ViewModels instead of Block classes. Without explicit guidance, Claude Code cannot reliably tell which pattern is the current standard and which represents technical debt. Making that distinction is exactly the job of the first CLAUDE.md, before any productive work begins on the code.
2. The first 30 minutes: starting Claude Code in an existing project
The built-in /init command scans the repository and automatically produces a first draft of a CLAUDE.md. That's a usable starting point, but not a finished result: the generated draft usually describes only what's visible in the code, not the reasoning behind decisions or the wrapper scripts the team actually works with. It's more effective to first assign Claude Code purely read-only tasks before anything gets written: list the directory structure, review commit history, inspect dependencies. That builds a shared picture of the codebase before any changes get proposed.
In practice, a short exploration pass right in the project root pays off, even before the CLAUDE.md exists at all. Claude Code can be asked specifically to summarize recurring naming conventions, directory depth, and the most frequently used design patterns. That summary then serves as raw material for the manually curated CLAUDE.md, instead of the model guessing again in every new session.
#!/usr/bin/env bash
# First exploration pass in an existing Magento project, read-only
set -euo pipefail
# Top-level module and directory structure, two levels deep
find app/code -maxdepth 2 -type d | sort
# Recent history to understand active areas of the codebase
git log --oneline -20
# Installed dependencies and versions actually in use
composer show --direct
# Detect mixed conventions: Preference vs Plugin usage across modules
grep -rl "preference" app/code --include="di.xml" | wc -l
grep -rl "<plugin " app/code --include="di.xml" | wc -l
# Rough size of the context surface Claude Code would face unfiltered
du -sh vendor generated var pub/static node_modules 2>/dev/null || true
3. Writing an effective CLAUDE.md
The CLAUDE.md is loaded into context in every session, functioning similarly to a project-specific system instruction. That's exactly why it should stay concise and action-oriented, not a copy of the README or the Composer dependencies. What matters is documenting things that can't be inferred from the code alone: why a specific wrapper is used instead of the direct CLI call, which deploy order is mandatory, which interface gaps are known and need to be worked around with a specific comment. That information saves repeated questions, or worse, wrong guesses, in every single session.
A proven structure organizes the CLAUDE.md into clearly separated sections: a project overview with tech stack versions, coding standards with concrete examples, a list of forbidden patterns, the available CLI wrapper commands, and the exact deploy sequence. Long prose sections are processed reliably by language models, but short, imperative rules with code examples tend to hold up better in practice than narrative description. A section with five clear prohibitions is more reliable than a paragraph that mentions the same prohibitions only in passing.
#!/usr/bin/env bash
# Bootstrap a curated CLAUDE.md instead of relying only on the auto-generated draft
cat > CLAUDE.md <<'EOF'
# Project: mironsoft.de Magento 2 Shop
## Stack
- Magento 2.4.8-p4, PHP 8.4, Hyva Theme, Tailwind CSS v4, Alpine.js
## Hard rules
- Never call `php bin/magento` directly, always use `bin/magento` wrapper
- Prefer ViewModels (ArgumentInterface) over Block classes
- Use Plugins, not Preferences, for extending core behavior
- declarative schema (db_schema.xml), never InstallSchema/UpgradeSchema
## Known interface gaps (always add // @phpstan-ignore-next-line)
- PageInterface::getData() is missing from the interface but exists on the model
## Deploy sequence (always in this order)
1. bin/npm --prefix <theme>/web/tailwind run build
2. rm -rf var/view_preprocessed/* pub/static/frontend/*
3. bin/magento setup:static-content:deploy de_DE -f
4. bin/magento cache:flush
EOF
4. Making project conventions and forbidden patterns explicit
In a grown codebase, describing what should be done isn't enough. At least as important is an explicit list of what should not be done, even though it's visibly present elsewhere in the same project. Claude Code orients heavily toward existing code as a model to follow. If the codebase still contains jQuery remnants from a migration off Luma to Hyvä, without an explicit prohibition the model may interpret those patterns as a valid template and continue them, instead of recognizing them as legacy baggage.
A concrete example from Hyvä projects: no Knockout.js, no jQuery, no UI Components, only Alpine.js for interactivity, consistently. That rule as a single sentence in the CLAUDE.md is rarely enough on its own. A short before-and-after example that shows exactly what a typical interaction pattern should look like in the project is more effective. Code examples act as a stronger anchor than abstract rules because they give the model a concrete target shape to follow, instead of just a prohibition list without context.
// FORBIDDEN in this project: legacy jQuery pattern from the old Luma theme
$('#qty-input').on('change', function () {
$.ajax({
url: '/checkout/cart/updateQty',
data: { qty: $(this).val() }
});
});
// REQUIRED pattern: Alpine.js component, no jQuery, no extra script tags
// x-data component defined in the phtml template, CSP-safe inline script
document.addEventListener('alpine:init', () => {
Alpine.data('qtyUpdater', () => ({
qty: 1,
async updateQty() {
await fetch('/checkout/cart/updateQty', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ qty: this.qty })
});
}
}));
});
5. Protecting the context window: what must be excluded
A Magento 2 repository contains, alongside the actual application code, large amounts of generated and downloaded material: vendor/, generated/, var/, pub/static/, and node_modules/ can together amount to several gigabytes and hundreds of thousands of files. None of these files contain information relevant to decisions in your own code, yet they cost tokens and can potentially steer the model toward compiled or minified versions instead of the actual source. A .claudeignore file, following gitignore syntax, consistently filters such paths out of automatic context intake.
Beyond sheer size, there's a content-based reason for the exclusion: generated/ contains automatically produced factory and proxy classes that get rewritten on every setup:di:compile. If Claude Code references code in that directory, it's referring to a transient artifact rather than the actual source in the module. Beyond the ignore file, it's worth a second look at permission configuration: write access can be scoped specifically to certain directories, so that even accidental write attempts into vendor/ get blocked outright, rather than merely being discouraged.
#!/usr/bin/env bash
# Create .claudeignore to keep build artifacts and vendor code out of context
cat > .claudeignore <<'EOF'
vendor/
generated/
var/
pub/static/
node_modules/
*.min.js
*.min.css
.git/
EOF
# Restrict write access via Claude Code permission settings
cat > .claude/settings.json <<'EOF'
{
"permissions": {
"allow": [
"Bash(bin/magento:*)",
"Bash(bin/composer:*)",
"Bash(bin/npm:*)",
"Edit(app/code/**)",
"Edit(app/design/**)"
],
"deny": [
"Edit(vendor/**)",
"Edit(generated/**)",
"Edit(.env)",
"Bash(rm -rf:*)"
]
}
}
EOF
6. Practical example: onboarding a Magento 2 project
A realistic scenario: an agency takes over an existing Magento 2.4.8 store with a Hyvä theme that was maintained by rotating developers over three years. The goal is to get Claude Code productive on day one, without it proposing risky changes to critical areas. The first step is /init in the project root, followed by manually revising the generated draft: adding the wrapper scripts under bin/, explaining the project's dual-vendor structure, and listing known PHPStan interface gaps that would otherwise show up as errors on every single run.
A verification step that has proven itself in practice follows next: Claude Code is asked to summarize the conventions it identified in its own words before the first write task follows. If the summary diverges from reality, that immediately reveals a gap in the CLAUDE.md that can be closed with little effort. The first actual tasks should be deliberately low-risk, such as adding missing PHPDoc blocks or fixing PHPCS violations, rather than working directly on the database layer or payment processes.
7. Refining CLAUDE.md iteratively instead of writing it once
The most common misjudgment during onboarding is treating the CLAUDE.md as a one-time setup document. In practice, only actual work on the code reveals which assumptions are missing. If Claude Code repeatedly calls php bin/magento instead of the project-specific wrapper, that's not random, it's a signal that the rule in the CLAUDE.md is either missing or not phrased clearly enough. Such corrections should be added directly as a new rule, instead of being repeated manually in every session.
It makes sense to treat the CLAUDE.md like regular code under version control and to review changes in code review, rather than negotiating them informally in chat. Corrections that keep coming up in review are good candidates for an explicit rule. Just as important is the opposite: outdated rules that stem from a migration that has since concluded should be removed, so the file doesn't grow indefinitely and lose precision over time.
8. Security and permissions in existing projects
A key distinction between the CLAUDE.md and Claude Code's permission and hook mechanisms: the CLAUDE.md is an instruction the model generally follows, but not a hard technical boundary. For genuinely critical areas, such as production-adjacent configuration files, credentials, or the vendor/ directory, a text rule alone isn't enough. This is where permission settings and hooks come in, technically refusing certain tool calls regardless of what the model proposes in a given session.
A PreToolUse hook, for instance, can inspect every write attempt and hard-reject changes to protected paths before they're ever executed. That's especially relevant in existing projects where sensitive files like .env or deployment scripts with production access live in the same repository as the actual application code. Combining CLAUDE.md for soft conventions with hooks for hard boundaries delivers an overall far more reliable security model than a prompt-based instruction alone.
#!/usr/bin/env python3
# PreToolUse hook: hard-block writes to vendor/, generated/ and .env
# regardless of what the CLAUDE.md instructions say
import json
import sys
BLOCKED_PATH_PREFIXES = ("vendor/", "generated/", ".env")
def main() -> int:
payload = json.load(sys.stdin)
tool_input = payload.get("tool_input", {})
file_path = tool_input.get("file_path", "")
for prefix in BLOCKED_PATH_PREFIXES:
if prefix in file_path:
print(json.dumps({
"decision": "block",
"reason": f"Writes to '{prefix}' are hard-blocked by project policy"
}))
return 0
print(json.dumps({"decision": "allow"}))
return 0
if __name__ == "__main__":
sys.exit(main())
9. Onboarding practice compared side by side
Most onboarding problems with Claude Code in existing projects trace back to a small number of recurring decisions. The table below contrasts insufficient practice with the recommended approach.
| Area | Insufficient | Recommended | Effect |
|---|---|---|---|
| Initial context | Turn it loose on the whole repo immediately | /init + manual curation before the first write task | Fewer wrong assumptions about conventions |
| Scope of CLAUDE.md | Long copy of the README | Short, imperative rules with code examples | Rules are followed more reliably |
| Context exclusion | vendor/, var/, generated/ in context | .claudeignore covering all build artifacts | Smaller context window, lower token cost |
| Forbidden patterns | Only implicit in existing code | Explicit prohibition list with before-and-after example | Less repetition of legacy baggage |
| Permissions | Unrestricted write access across the whole repo | Permissions and hooks for vendor, .env, .git | A hard safety net instead of pure trust |
None of these measures is expensive on its own, but their effect compounds. A project that combines .claudeignore, a curated CLAUDE.md, and hard permission rules at the same time reduces both the error rate and the risk of unintended changes to critical files far more than any single measure alone.
Mironsoft
Magento 2 and Hyvä development with Claude Code in the daily workflow
Ready to integrate Claude Code cleanly into your project?
We build a curated CLAUDE.md for your Magento or PHP project, define context exclusions, and set up permission rules, so Claude Code works safely and productively from day one.
CLAUDE.md audit
Reviewing an existing or missing CLAUDE.md and extending it precisely
Context setup
.claudeignore and permission configuration for existing projects
Team onboarding
Workflows and hooks for everyday use across the development team
10. Summary
Integrating Claude Code into an existing project is not a one-time configuration task, it's a process that starts with deliberate exploration and continues for the entire lifetime of the project. A curated CLAUDE.md with clear, imperative rules clearly outperforms an automatically generated documentation copy. Exclusion rules for vendor/, generated/, and other build artifacts keep the context window focused on actually relevant code. Explicit prohibition lists with before-and-after examples prevent Claude Code from unintentionally continuing historically grown anti-patterns as if they were the current standard.
The most important structural point remains the separation between soft guidance via the CLAUDE.md and hard technical enforcement via permissions and hooks. Text rules reliably steer the model's behavior in the vast majority of cases, but they don't substitute for a technical boundary on genuinely critical paths like credentials or third-party code. Combining both, and maintaining the CLAUDE.md as a living, versioned document, results in a setup that grows with the project instead of going stale after the first session.
Claude Code in Existing Projects - The Essentials at a Glance
Curate CLAUDE.md
Use /init as a starting point, but manually add wrapper commands, deploy sequence, and known gaps.
Scope context deliberately
Set up .claudeignore for vendor/, generated/, var/, node_modules/, and build artifacts.
Make prohibitions explicit
Clearly flag old patterns like jQuery or Preferences as forbidden, with a concrete code example.
Enforce hard boundaries
Permissions and PreToolUse hooks for .env, vendor/, and .git back up CLAUDE.md rules technically.