Stop your agent
grepping around.
One call gives your coding agent the map: where to start, what a change breaks, which tests to run.
Project map
The tree, with .gitignore respected
src/click├── __init__.py├── _compat.py├── _termui_impl.py├── _textwrap.py├── _utils.py├── _winconsole.py├── core.py├── decorators.py├── exceptions.py├── formatting.py├── globals.py├── parser.py├── py.typed├── shell_completion.py├── termui.py├── testing.py├── types.py└── utils.py 0 directories, 18 files
Reading order
What the project is and what to read first
Tour of click Purpose (README.md excerpt): Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It's the "Command Line Interface Creation Kit".26 directories, 178 files (7 entries ignored or skipped)Ecosystem: Python (pyproject.toml; pip/poetry/uv)Languages: Python 63%, Markdown 29%, YAML 6%, JSON 1%, Shell 1% Layout (top-level directories): docs/ (41 files) examples/ (39 files) src/ (18 files) tests/ (59 files) Start here: 1. README.md — project overview (README) 2. src/click/_compat.py — used by 9 files 3. src/click/utils.py — used by 9 files 4. src/click/core.py — used by 8 files 5. src/click/exceptions.py — used by 7 files 6. src/click/globals.py — used by 6 files 7. src/click/__init__.py — used by 3 files 8. src/click/formatting.py — used by 3 files +9 reading candidates omitted; raise --limit (maximum 50). Next (run from the directory you toured; POSIX shell or PowerShell): sprout context './src/click/_compat.py' sprout --ai sprout -L 2 Note: suggestions are heuristics from static analysis, not runtime behavior.
What changed
A branch or commit range, as a tree
src HEAD~5└── click/ (6 changed) +388 -132 ├── _utils.py M +9 -0 ├── _winconsole.py M +0 -5 ├── core.py M +320 -81 ├── termui.py M +10 -0 ├── types.py M +29 -14 └── utils.py M +20 -32 6 files changed, +388 -132
Context
What to know before editing a file
# src/click/decorators.py3 dependencies · 2 direct users · 12 affected through them · 43 tests reach it ## depends on (and what it uses from each)src/click/core.py — imports .core class Context class Command class Group(Command) class Parameter(ABC) +2 moresrc/click/globals.py — imports .globals def get_current_context(silent: t.Literal[False] = False) -> Context: ... def get_current_context(silent: bool = ...) -> Context | None: ... def get_current_context(silent: bool = False) -> Context | Nonesrc/click/utils.py — imports .utils def echo(…) ## used bysrc/click/__init__.py — imports .decoratorssrc/click/core.py — imports .decorators ## tests that reach ittests/test_context.pytests/test_abort_interrupt.pytests/test_arguments.pytests/test_basic.pytests/test_chain.pytests/test_command_decorators.pytests/test_commands.py+2 more ## declaresdef pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]def make_pass_decorator(…)def pass_meta_key(…)def command(name: _AnyCallable) -> Command: ...+16 more
Impact
Every file a change reaches, and the tests to run
Impact of 1 file src/click/core.py Affected: 12 files, 8 directly src/click/__init__.py imports .core src/click/decorators.py imports .core src/click/exceptions.py imports .core src/click/globals.py imports .core src/click/parser.py imports .core src/click/shell_completion.py imports .core src/click/testing.py imports .core src/click/types.py imports .core … and 4 more files through them (--all lists them) Tests: 43 files python -m pytest tests/test_abort_interrupt.py tests/test_arguments.py tests/test_basic.py tests/test_chain.py tests/test_command_decorators.py tests/test_commands.py tests/test_compat.py tests/test_context.py tests/test_custom_classes.py tests/test_defaults.py tests/test_deprecations.py tests/test_exceptions/test_FileError.py (runs 12 of 43; --all prints the full command)
Rules
Imports that break .sproutrules
1 import breaks .sproutrules (18 files checked) .sproutrules:5 src/click/formatting.py -> src/click/parser.py src/click/formatting.py -> src/click/parser.py imports .parser
Maps all 31,412 files of Kubernetes in 0.23 s. From a weekend script to a monorepo, one binary and no account.
Reads:
- Go
- TypeScript
- JavaScript
- Python
- Rust
- Java
- Kotlin
Works with:
- Claude Code
- Cursor
- VS Code
- Claude Desktop
- any MCP client
Which tests run after I change src/click/core.py?
pallets/click · Sprout v0.4.2 · tokens = characters ÷ 4
1 call, not 42
Every test a change reaches, in 225 tokens
# the library never imports its testssrc/ -> tests/# low-level helpers stay below the command layersrc/click/utils.py -> src/click/core.pysrc/click/formatting.py -> src/click/parser.py
1 import breaks .sproutrules (18 files checked) .sproutrules:5 src/click/formatting.py -> src/click/parser.py src/click/formatting.py -> src/click/parser.py imports .parser
Rules for CI
Fail the build on a forbidden import
src/click├── __init__.py├── _compat.py├── _termui_impl.py├── _textwrap.py├── _utils.py├── _winconsole.py├── core.py├── decorators.py├── exceptions.py├── formatting.py├── globals.py├── parser.py├── py.typed
The tree
Respects .gitignore, counts what it hides
project_mapThe map, key files and signaturesreading_orderWhere to start, and whyimpactWhat could break, and the tests to runcontextWhat a file uses, its users and testsdepsWhat a file usesdependentsWhat uses a filetreeAny folder as a treediff_treeWhat a branch changed
8 MCP tools
One server, any agent
# src/click/decorators.py3 dependencies · 2 direct users · 12 affected through them · 43 tests reach it ## depends on (and what it uses from each)src/click/core.py — imports .core class Context class Command class Group(Command) class Parameter(ABC) +2 moresrc/click/globals.py — imports .globals def get_current_context(silent: t.Literal[False] = False) -> Context: ... def get_current_context(silent: bool = ...) -> Context | None: ... def get_current_context(silent: bool = False) -> Context | None
Context
What to know before editing a file
Above groundThe files you can see.
Below groundHow they connect. Sprout maps it.
Same answer. For you and your agent.
The CLI prints it for you
Plain text in your terminal, or --json for scripts. The MCP server hands your agent the same answer.
Read-only. Paths stay inside the project, and every call reads the disk again.
One line to connect
Any MCP client works. Setup and safety →
Questions
More in the FAQ.
Does Sprout send my code anywhere?
No. It makes no network requests except to clone a repository you asked it to map. The map holds names and signatures, never function bodies.
How is it different from grep?
grep finds text. Sprout resolves imports the way each language does, so it knows which files depend on which, including tests that reach a file through other files.
Which languages does it read?
Go, TypeScript, JavaScript, Python, Rust, Java and Kotlin. Any other file still shows in the tree.
Does it work with my agent?
Any MCP client: Claude Code, Cursor, VS Code and Claude Desktop have one-line setups. Without MCP, paste sprout --ai into any chat.
What does it cost?
Nothing. Sprout is MIT licensed, a single binary with no account and no telemetry.