exploring-codebases · v2.5.0 · 2026-08-25 · sha256 a995acd7a47864fd

exploring-codebases v2.5.0A

Immutable. This exact content is served forever at /api/v1/blob/a995acd7a47864fd.

---
name: exploring-codebases
description: >-
  First-encounter orientation on a repository nobody here has worked in yet.
  Runs a fixed five-step workflow — venv setup, tarball fetch, tree-sitting
  structural scan, featuring synthesis, then reasoning over the two — and
  yields an account of what the repo contains and how it is arranged,
  optionally written out as _FEATURES.md. Use for "I just cloned this",
  "what is this repo", "what does this do", "explore this repo", "give me an
  orientation", "what are the main features", "review what's new in <repo>",
  or before starting work in a codebase you have not seen. This is the
  divergent what's-here skill. Route elsewhere for: a named symbol, a file's
  structure or a line range (tree-sitting); all callers of a Python symbol
  (searching-codebases); teaching a human the codebase through exercises
  (orienting-codebases); fetching or cloning a repo without analysing it
  (accessing-github-repos, cloning-project).
metadata:
  version: 2.5.0
---

# Exploring Codebases

Exploratory code analysis for unfamiliar repositories. Orchestrates
tree-sitting (structural) and featuring (semantic) over a local copy.

## Workflow

Five numbered steps, in order. Do not skip step 0.

### 0. Setup (once per session)

```bash
uv venv /home/claude/.venv 2>/dev/null
uv pip install tree-sitter --python /home/claude/.venv/bin/python
export PYTHON=/home/claude/.venv/bin/python
export TREESIT=/mnt/skills/user/tree-sitting/scripts/treesit.py
export GATHER=/mnt/skills/user/featuring/scripts/gather.py
```

If step 2's `--stats` reports `Symbols: 0` on a repo you know contains code,
the `tree-sitter` core package isn't installed — come back here and install it
(the engine bundles its own grammars and does NOT use tree-sitter-language-pack).
Treesit exits 0 and prints no error in that case, so zero symbols is the only
signal you get. There is no `Errors:` line: that one appears for parse
failures, and an absent parser never reaches parsing. The full signal, and the
2026-08-24 measurement behind it, is in the tree-sitting skill's Setup section.

### 1. Get the repo (tarball, not per-file)

```bash
OWNER=...
REPO=...
REF=main                    # branch name, tag, or SHA. For a PR: pull/N/head
curl -sL -H "Authorization: Bearer $GH_TOKEN" \
  "https://api.github.com/repos/$OWNER/$REPO/tarball/$REF" -o /tmp/$REPO.tar.gz
mkdir -p /tmp/$REPO && tar -xzf /tmp/$REPO.tar.gz -C /tmp/$REPO --strip-components=1
ls /tmp/$REPO | head        # sanity check — did extraction land?
```

One HTTP call gets the whole repo. Do NOT curl README, cat files, or
fetch via `contents/PATH` first — they're in the tarball. The
Authorization header is only needed for private repos; public repos
work without it.

**Ref selection matters.** If exploring a feature branch, PR, or tag,
set `REF` accordingly. The default `main` will silently give you stale
code if the question is about an unmerged branch.

### 2. Structural scan

```bash
$PYTHON $TREESIT /tmp/$REPO --stats
```

Read the output. It gives file counts, symbol counts, languages, and
per-directory symbol density. This IS the orienting artifact — treat it
as the product of this step, not warm-up.

**Drill only if you have a specific question.** For pure "what is this
repo" exploration, skip drilling and go to step 3 — featuring surfaces
the interesting paths for you. Drill when a user asked about a specific
subsystem, or when step 3's output raises a question that needs source.

**When you do drill, batch queries in one invocation.** Every treesit
call pays the full scan cost. Multiple queries added to the same command
share that scan and each additional query adds ~0ms. If you're about to
make a second treesit call on the same path, fold it into the first.

```bash
# GOOD — one scan, three answers
$PYTHON $TREESIT /tmp/$REPO --path=SUBDIR --detail=full \
  'find:*Handler*:function' 'source:main' 'refs:Config'

# BAD — three scans, three answers (3× the cost for the same information)
$PYTHON $TREESIT /tmp/$REPO --path=SUBDIR --detail=full
$PYTHON $TREESIT /tmp/$REPO 'find:*Handler*:function'
$PYTHON $TREESIT /tmp/$REPO 'refs:Config'
```

### 3. Feature synthesis

**Pick the mode from your DELIVERABLE, before you run it.**

| Your deliverable | Command | Size |
|---|---|---|
| Your own understanding — a review, an orientation read, answering a question | `--orient` | ~115 lines |
| A written `_FEATURES.md` that must cite every symbol | full output | thousands of lines |

```bash
# Default. Complexity assessment, decomposition ranking, directory tree, entry points.
$PYTHON $GATHER /tmp/$REPO --skip tests,.github,node_modules --orient

# Only when you are about to WRITE the inventory into a file:
$PYTHON $GATHER /tmp/$REPO --skip tests,.github,node_modules --source-budget 8000
```

Output includes a "Candidate areas for sub-files (by symbol density)"
list near the top — that's your drill-target picker, ranked.

**Never pipe the full output through `head`.** If you are about to truncate it,
`--orient` was the correct mode and you have paid for thousands of lines you
will not read. Diagnosed 2026-08-22 on a FreeToken review: a 5,697-line gather
was cut at line 120, and every finding in that review came from `treesit`
drilling and targeted reads instead. `--orient` returns the 115 lines that were
actually used. The full mode's symbol inventory exists to be CITED, not read.

### 4. Reason about the combined output

Synthesize 2+3: capabilities, feature groups, architecture, entry
points, anomalies. Produce `_FEATURES.md` when warranted. This is the
LLM step; everything before was mechanical.

## When to Use This vs Other Skills

| Situation | Use |
|-----------|-----|
| "I just cloned this, what is it?" | **exploring-codebases** (this skill) |
| "Where is the retry logic?" | searching-codebases |
| "Find all files matching `class.*Error`" | searching-codebases |
| "Show me the symbols in auth.py" | tree-sitting directly |
| "Which files are most about CSRF / sessions / queryset filtering?" | bm25 |
| "Rank these docs by relevance to a multi-word concept" | bm25 |
| "Document what this codebase does" | featuring directly |
| "Teach me this codebase" (a human is learning) | orienting-codebases |
| "Get me this repo" — fetch, no analysis | accessing-github-repos, cloning-project |

Exploring is the **divergent** skill — you don't know what you're looking
for yet. Searching is the **convergent** skill — you know what you want.

`orienting-codebases` runs the same tree-sitting + featuring pipeline and is
the nearest thing in the catalogue to this skill. The split is the audience:
this one builds Claude's understanding so work can proceed; that one builds
the *user's* understanding through guided exercises and HTML artifacts. If
nobody is being taught, this is the right skill.

### Pairing bm25 with this workflow

Once steps 2–3 have surfaced the rough shape of the repo, `bm25` is the
natural complement when you want **ranked content search** beyond grep
and beyond exact-symbol lookup. It ranks files by lexical relevance to a
multi-word query, which is useful for "what's this codebase actually
*about* when I search for X?" — particularly when you don't yet know the
symbol name to feed to `tree-sitting`.

```bash
BM25=/mnt/skills/user/bm25/scripts/bm25.py

# Pass multiple queries — index builds once, all queries reuse it
python3 $BM25 /tmp/$REPO 'auth flow' 'session backend' 'middleware pipeline' \
  --exclude 'tests/*' --exclude '*/tests/*' --top-k 5
```

Two patterns that pair especially well:

1. **bm25 → tree-sitting.** Use bm25 to find the top-ranked files for a
   concept; then `tree-sitting source:Symbol:path/to/file.py` to read
   the actual implementation.
2. **bm25 with `--exclude 'tests/*'`.** Test directories tend to dominate
   keyword queries because test names redundantly mention domain terms.
   Excluding them up front lands you on implementation files.

bm25 is corpus-agnostic — it'll also work on `project` knowledge stores
or `uploads/` if your exploration spans docs, transcripts, or PDFs.

## Delegating to subagents

Only when the repo is large (>1000 files or several distinct subsystems) **and**
this environment exposes a subagent tool (Agent/Task in Claude Code and CCotw).
Claude.ai chat and bare-skill runs have none: run steps 2-4 inline and skip
this entirely. Never simulate fan-out by other means when the tool is absent.

Steps 2-3 stay inline either way. Only step 4's judgment work fans out, one
agent per subsystem, and a subagent inherits nothing -- not the conversation,
not this file, not the knowledge that scan artifacts are already on disk.
Read [references/subagent-delegation.md](references/subagent-delegation.md)
before writing the first agent prompt; it carries the four things every prompt
must include and the 2026-07-16 measurement of what happens when they are
missing.

## Notes

- **Large repos (>100 files)**: use `--skip tests,vendored,docs,...` in
  step 2 to focus the scan.
- **Monorepos**: treat each package/service as a separate exploration.
  Generate per-subsystem `_FEATURES.md` files linked from a root index.
- **Drill heuristics** (if step 2 drilling is warranted): directories
  with high symbol-to-file ratio (dense logic), entry-point names
  (`main`, `cli`, `app`, `server`, `routes`), files with many imports
  (integration points).