repo-map
Map a repository as a Markdown tree with LLM-written notes on each file.
repo-map walks a repository, sends each eligible file to an OpenRouter model, and writes the results as a tree to <repository>_repo_map.md. Analyses are cached in SQLite, so the next run only re-sends files that changed.
Each file gets a description, the one thing a contributor is most likely to get wrong, a maintenance flag, an architectural role, its critical dependencies, and a refactoring suggestion or security note when one applies. An entry from examples/example.md, which is repo-map run on itself:
├── main.py (Python)
│ ├── Description: Console-script entrypoint for repo-map. run_main() configures logging, imports RepoMapApp lazily, runs RepoMapApp().run() under asyncio.run, and maps failures to exit codes: 1 for configuration errors and unexpected exceptions, 130 for Ctrl-C.
│ ├── Developer Consideration: The RepoMapApp import inside run_main() is deliberate: importing cli_handler builds the settings singleton and rate limiter, and a ValueError there (e.g. bad API_SEMAPHORE_LIMIT) must be caught after setup_logging(). Moving it to module scope breaks that handling.
│ ├── Maintenance Flag: Stable
│ ├── Architectural Role: Entrypoint
│ ├── Critical Dependencies:
│ ├── - repo_map.logging_utils: setup_logging() configures logging before any application code or errors run.
│ └── - repo_map.cli_handler: Supplies RepoMapApp, the application whose async run() does all the work.
Getting started
Set an OpenRouter API key, then run repo-map with uv, no install step needed:
export OPENROUTER_API_KEY=sk-or-...
uvx repo-map /path/to/repository
To keep it installed instead:
uv tool install repo-map
repo-map /path/to/repository
Requires Python 3.12 or newer. repo-map asks for confirmation before it sends anything; -y skips the prompt.
Configuration
Settings come from the environment, or from a .env file in the directory you run repo-map from. .env.example lists them all.
| Variable | Required | Default | Purpose |
|---|---|---|---|
OPENROUTER_API_KEY |
Yes | OpenRouter API key | |
OPENROUTER_MODEL_NAME |
No | anthropic/claude-sonnet-5.5 |
Any OpenRouter model ID |
API_SEMAPHORE_LIMIT |
No | 3 |
Concurrent API calls |
Usage
repo-map /path/to/repository [-y] [--model MODEL] [--concurrency N]
| Option | Purpose |
|---|---|
-y, --yes |
Skip the upload confirmation |
--model MODEL |
Override OPENROUTER_MODEL_NAME for this run |
--concurrency N |
Override API_SEMAPHORE_LIMIT for this run |
A run writes three files into the target repository. Add them to its ignore rules if you don't want them committed.
| File | Contents |
|---|---|
<repository>_repo_map.md |
The report |
.repo-map-cache.db |
Cached analyses, keyed by repository-relative path |
.repo_map_structure.json |
The scanned structure, before analysis |
A cached analysis is reused while the file's SHA-256 hash, the model, and repo-map's analysis contract all still match. Editing a file, switching --model, or upgrading to a release with a revised prompt triggers re-analysis. Each run prunes entries for files it no longer finds, and the cache stays valid when the repository is renamed or cloned elsewhere.
What gets sent
Each request carries the repository's file and directory names, short descriptions of the files the target imports or shares a directory with, and the full text of the target file. Review the repository and its ignore rules before approving a run, and don't analyze secrets or source you aren't authorized to share with OpenRouter.
A file's source is sent only if it is a regular file (symlinks are never followed) in a supported text format, at most 64 KiB, valid UTF-8, and free of NUL bytes. Binary and media formats are never sent.
repo-map skips these paths by default, then applies the target's root .gitignore. An excluded directory is not traversed, so nothing inside it is read or sent.
| Group | Patterns |
|---|---|
| Version control | .git/, .hg/, .svn/, CVS/ |
| Caches and bytecode | __pycache__/, *.pyc, *.pyo, *.pyd, .pytest_cache/, .mypy_cache/ |
| Environments and dependencies | .venv/, venv/, env/, node_modules/ |
| Build output | build/, dist/, *.egg-info/ |
| Credential-bearing config | .env, .envrc, *.tfvars, *.tfstate, *.ini, *.conf, *.cfg |
| Databases and logs | *.db, *.sqlite3, *.log |
| Local noise and repo-map output | .DS_Store, .repo-map-cache.db, .repo_map_structure.json, *_repo_map.md |
Matching follows gitignore's last-match-wins rule, so a negation in the target's .gitignore, such as !app.conf, brings an excluded file back. Only the root .gitignore is read.
Project structure
| Path | Purpose |
|---|---|
src/repo_map/ |
The package: CLI, scanner, parsers, OpenRouter client, cache, and report writer |
tests/ |
pytest suite, one module per source module |
examples/example.md |
repo-map's report on this repository |
changelog/ |
Per-version release notes; CHANGELOG.md is the generated index |
scripts/build-changelog.ts |
Builds CHANGELOG.md from changelog/ |
.claude/skills/ |
Agent workflows for maintaining this repository |
Development
git clone https://github.com/cyanheads/repo-map.git
cd repo-map
uv sync
make check
make checkis the gate: Ruff lint and format check, pyright, pytest,uv lock --check, and the changelog index check. The changelog step runs under Bun.- A change to the prompt or the response fields bumps
ANALYSIS_CONTRACT_VERSIONinsrc/repo_map/llm_service.py, so cached analyses made under the old contract are redone. CHANGELOG.mdis generated: addchangelog/<major.minor>.x/<version>.md, then runmake changelog.CLAUDE.mdhas the full set of working rules.
Contributing
Bugs and feature requests go through the issue forms; CONTRIBUTING.md covers what makes one actionable. Report vulnerabilities privately as described in SECURITY.md.
License
Apache-2.0. See LICENSE.
Metadata
Release files for repo-map 0.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| repo_map-0.14.0.tar.gz | 33.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| repo_map-0.14.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 73.0 kB
Release files / repo_map-0.14.0.tar.gz
| Download URL | repo_map-0.14.0.tar.gz |
|---|---|
| Size | 33.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
64d3798578049abf68673ccb2e4ddada309e44b6557d1b97fd9726c8c814b0bb
|
|
BLAKE2b-256 checksum How to use checksums |
e5f6cabd6342ede07dad1651956b7a561b60d7fc870881a3be38dce9819bcc13
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / repo_map-0.14.0-py3-none-any.whl
| Download URL | repo_map-0.14.0-py3-none-any.whl |
|---|---|
| Size | 39.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
add2ea3228febd4e605e8175951f077126fb4d3c8800599c739296ea41bb9b8c
|
|
BLAKE2b-256 checksum How to use checksums |
cecc2fe00adf78cc5bdf57c624be96b893f15cef5e527ecd5aa6f3732cfc3100
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for repo-map 0.14.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.