Build a breadth-first map of an unfamiliar codebase in a bounded amount of time - entry points, module boundaries, persistence and integration surface, churn hotspots, test topology, config surface, and landmines - then write it up as a durable system map plus a working CLAUDE.md. Use when dropped into a codebase you do not know, when asked "help me understand this repo", when you need to know where a change would land before committing to anything, or when inheriting a system whose original authors have left. Deliberately maps the territory rather than exploring any one region deeply. Run before feasibility-probe or trace-the-flow. Do not use when a current system map already exists, or when the user is asking you to implement a change.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Build a breadth-first map of an unfamiliar codebase in a bounded amount of time - entry points, module boundaries, persistence and integration surface, churn hotspots, test topology, config surface, and landmines - then write it up as a durable system map plus a working CLAUDE.md. Use when dropped into a codebase you do not know, when asked "help me understand this repo", when you need to know where a change would land before committing to anything, or when inheriting a system whose original authors have left. Deliberately maps the territory rather than exploring any one region deeply. Run before feasibility-probe or trace-the-flow. Do not use when a current system map already exists, or when the user is asking you to implement a change.
Repo recon
The first structured pass over an unfamiliar system.
Why this exists
Dropped into a large codebase, the instinct is to start reading. After two hours you know one component and cannot answer the questions people are about to ask. This skill trades depth for coverage: where things are and what you'd be scared to touch. Depth is trace-the-flow, later, only where the work lands. A map that exists only in this session is worthless in week three.
When this applies
Any unfamiliar codebase you'll work in for more than a day
Before estimating, designing, or changing anything
Inheriting a system whose authors have left
Someone asks what a repository does and you don't know
When it doesn't
You already know the system — read CLAUDE.md and go
You need one specific fact — grep for it
The repository is small enough to read outright (under ~500 files)
You need deep behavior of a single flow — that's trace-the-flow
Prerequisites
Locate the workspace (../_shared/workspace-conventions.md)
00-engagement.md — scopes what you're looking for
00c-context.md / 01-environment.md(optional) — budget and whether it builds
Read ../_shared/stack-detection.md before step 2, including Searching after detection
On anything over ~5,000 files, apply context-strategy first and set a budget
Procedure
Ordered cheapest to most expensive. Each step should sharpen where the next one looks. Read the stopping test in step 10 before you start — it's what stops this becoming a week.
You're establishing: how big, what languages, is it alive, is it one system or several. A repository with three commits in six months and a top language you didn't expect is telling you something before you read a line.
2. Stack
Follow ../_shared/stack-detection.md. Record every stack present with its root, and state which one you're scoping to. In enterprise repositories, several is the norm, not the exception.
Read the CI configuration properly at this point. It is the single most informative file for an arriving engineer: the real build and test commands, the pinned versions, the service dependencies, and the deploy path.
3. Entry points
How does anything get into this system? Everything else hangs off the answer.
Read references/entry-points-by-stack.md before searching. Three checks in that reference come before any language-specific pattern, and skipping any of them produces a confidently wrong map:
Are the files even authored? A setup.py and thousands of .py files can be openapi-generator output. If .openapi-generator/ exists or most sources say "do not edit" / "generated by", split authored vs generated before mapping. The spec and the handwritten remainder are the system.
Are the entry points in the code at all? They may be declared in XML, YAML, JCL, CICS CSD, BMS maps, copybooks, or a database table. The tell is extension counts from step 1: if non-source artifacts rival the compiled language, the application lives in those artifacts. XML/YAML/JSON is one case, not the definition.
Does this codebase use its framework's vocabulary? Mature systems wrap framework primitives in house abstractions, so the canonical interface name returns nothing.
Then use the section matching what step 2 detected. Do not run patterns for a stack you didn't detect — "few hits" reads as "few entry points" rather than "wrong search," and that failure is silent.
Before searching, establish the deployment shape — service, CLI, library, batch, event consumer, serverless. Entry points differ more by shape than by language, and most real systems are two or three shapes at once. A CLI tool has no HTTP routes, and concluding it has no entry points because you searched for routes is a mistake you won't notice.
Then run the stack-independent sweep from the same reference. Non-obvious entry points are where surprises live. If a 1,300-file codebase appears to have two entry points, you searched wrong — say so and re-search.
4. Boundaries and layering
Which modules exist, and which direction do dependencies run?
# Top-level packages — do not assume a src/ directory
find . -maxdepth 3 -type d -not -path "*/.git*" -not -path "*/node_modules*" -not -path "*/vendor*" | sort
Do not grep ^(import |using |from ). That is three languages' syntax. On Elixir it returns 0 while alias/use/import appear hundreds of times, indented. Use the module-reference form in references/entry-points-by-stack.md for the detected stack, or skip the count and map directories by name. A "domain" package depending on "web" is the finding — the import keyword is just a means.
You're looking for the intended architecture and where reality departs from it.
5. Persistence and integration surface
What does this system store, and what does it talk to? This is the highest-value step for blast-radius work later.
# Schema-like files. SQL is one dialect — also .ddl, IMS DBD, CSD. Then the# record form in entry-points-by-stack.md (copybook 01, DEFINE FILE, CREATE TABLE).
find . \( -path "*migration*" -o -iname "*schema*" -o -iname "*.sql" -o -iname "*.ddl" \
-o -iname "*.dbd" -o -iname "*.csd" \) | head -30
# Outbound calls and external hosts
grep -rnE "https?://[a-zA-Z0-9.-]+" --include="*.yml" --include="*.yaml" --include="*.properties" --include="*.json" . \
| grep -v "schema\|xmlns\|w3.org\|localhost" | head -30
# Messaging — names, not one framework's listener annotation
grep -rn "topic\|queue\|exchange\|SQS\|ServiceBus\|pubsub" --include="*.yml" --include="*.$EXT" . | head -30
docker-compose.yml, if present, usually names every database, cache, broker, and stubbed downstream in one file. Read it — it's often the fastest dependency map available.
Filter the noise or the signal disappears. Manifests, lockfiles, changelogs, and generated trees (once step 3 identified them) top the list in almost every repository. --no-renames avoids a stall on large histories. If the clone is shallow, skip churn and tag it [unverified].
High-churn files are where the business is changing. The inverse — untouched for years — is either stable or load-bearing and forgotten. Both matter.
7. Test topology
Filenames first, then syntax. Assertion greps (def test_, func Test, #[test]) are language-specific and return 0 on ExUnit (test "…" do in *_test.exs).
Only then, if the stack's assertion form is listed in entry-points-by-stack.md, grep for it. Do not run every language's pattern "to be safe."
Watch for fixture directories masquerading as tests. Snapshot, golden-file, and input-corpus directories can hold hundreds of files and will dominate a file count while containing no test logic at all. A "top test location" with 216 files named snapshots/ is data, not tests.
Establish where tests live, what kinds exist, roughly how many, and whether CI gates the merge. The question that matters: is the code you'll change covered? If not, characterization-tests comes before any change.
Node/Python process.env / os.getenv greps miss System.get_env, Application.get_env, os.Getenv, and std::env. After detection, search that stack's env accessor, or list config/ and .env* and stop there. Never record values — locations only. See ../_shared/workspace-conventions.md.
9. Landmines
The section people actually read.
grep -rni "TODO\|FIXME\|HACK\|XXX\|WORKAROUND\|DO NOT" --include="*.$EXT" . | wc -l
# Generated-header density — a large number is a generation finding, not a todo list
grep -rl -i "generated by\|do not edit" --include="*.$EXT" . | wc -l
grep -rni "HACK\|DO NOT\|CAREFUL\|WARNING" --include="*.$EXT" . | head -25
Look for: comments warning future readers, generated files that must not be hand-edited, deprecated paths still in use, commented-out blocks near active code, retry and timeout constants that look arbitrary, anything named legacy, old, v1, or temp still on a live path. If the generated-header count is most of $EXT, go back to step 3 — you are standing in a build product.
Where a landmine looks deliberate, git-archaeology will usually tell you why in two minutes. The ugly branch is frequently an incident fix, and removing it re-opens the incident.
10. Stop
You have enough when you can answer these five without looking anything up:
Where does a request enter this system?
Where does its data live?
What else does it talk to?
Where would I add a feature like the one being asked for?
What would I be scared to touch, and why?
If you can answer all five, stop and write it up. Continuing is depth, and depth belongs to a skill with a specific question.
If you can't answer one after a reasonable pass, that gap is itself the finding — record it as [unverified] with what would resolve it. An honest map with a labelled hole beats a confident one that quietly omits a third of the system.
11. Write both artifacts
02-system-map.md is the engagement record. CLAUDE.md is the working aid that loads every session. They are different documents with different audiences — see context-strategy step 6 for what belongs in each. Extend an existing CLAUDE.md rather than replacing it.
Output template
Write to <workspace>/02-system-map.md:
# System map — <system>**Engagement:**<name>**Author:** FDE
**Date:**<YYYY-MM-DD>**Status:** draft
**Source revision:**<repo>@<shortSHA>**Confidence:**<coverage, and what you couldn't reach>## Scope<Whatthismapcovers, andexplicitlywhatitdoesn't.Requiredinamonorepo.>## At a glance-**Purpose:**<whatitdoes, onesentence, inbusinessterms>-**Size:**<n> files, ~<n> LOC
-**Stack:**<detected, with citation>-**Activity:**<n> commits in 6 months; last commit <date>-**Health:**<doesitbuild, dotestspass, isCIgreen>## Entry points
| Type | Entry | Handler | Notes |
|---|---|---|---|
| HTTP | `POST /api/orders` | `OrderController:44` | |
| Scheduled | nightly 02:00 | `ReconJob:19` | `[inferred: cron in config]` |
| Event | topic `payments.settled` | `SettlementListener:31` | |
## Module map
| Module | Responsibility | Depends on | Notes |
|---|---|---|---|
## Data
| Store | What lives there | Accessed via | Shared with |
|---|---|---|---|
## Integrations
| System | Direction | Protocol | Where configured | Owner |
|---|---|---|---|---|
## Test topology-**Location:** · **Kinds:** · **Count:** · **Runtime:** · **Gates merge:** yes/no
-**Coverage of the area we're changing:**<theanswerthatmatters>## Config and environments
| Environment | Config source | Notes |
|---|---|---|
## Churn hotspots
| File | Commits (12mo) | Why it matters |
|---|---|---|
## Landmines
| What | Where | Why it matters | Confidence |
|---|---|---|---|
## The five questions
Answer the five from step 10 here, cited.
## Gaps<Whatyoucouldnotestablish, andwhatwouldresolveit.>
Common traps
Depth-first drift. You open one interesting file and lose an hour. Note it as worth revisiting and move on — the map is the deliverable.
Mapping the whole monorepo. Above ~50,000 files, "I mapped the repo" isn't credible. Scope to a subtree and say so in the Scope section.
Trusting the README. It records what was true when someone last cared. CI config is ground truth; the README is a hypothesis.
Recording structure instead of meaning. "There is a services package containing 14 services" is a directory listing. Which ones matter, and why, is a map.
Confident silence about gaps. Omission reads as absence. A section you couldn't investigate must appear, labelled.
Skipping non-HTTP entry points. Batch jobs, queue consumers, and schedulers are where the surprises are.