sprout

command module
v0.4.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2026 License: MIT Imports: 31 Imported by: 0

README ΒΆ

🌱 Sprout

A map of your codebase for you and your AI agent: where to start reading, what a change could break, and which tests to run.

CI Release GitHub stars DeepSource Go version Docs Good first issues Discussions

sprout tour                           # what this project is, how it's laid out, what to read first
sprout impact                         # what your uncommitted changes could break, and the tests to run
claude mcp add sprout -- sprout mcp   # give Claude Code the same map (other agents: below)

Try it on any GitHub repo, no clone needed: sprout tour github.com/charmbracelet/bubbletea.

No install, with Go: go run github.com/Sprout-DevLabs/sprout@latest tour.

One small binary, standard library only. Reads Go, TypeScript/JavaScript, Python, Rust, Java and Kotlin. πŸ“– Docs Β· ⭐ If Sprout saves you or your agent some digging, a star helps others find it.

Install

Platform Command
macOS, Linux brew install sprout-devlabs/tap/sprout
Windows scoop bucket add sprout https://github.com/Sprout-DevLabs/scoop-bucket then scoop install sprout
Debian, Ubuntu, Fedora, Alpine, Arch .deb, .rpm, .apk and .pkg.tar.zst from Releases
Any Unix curl -fsSL https://sprout-devlabs.github.io/sprout-web/install.sh | sh (checks the SHA-256 before installing)
Go 1.22+ go install github.com/Sprout-DevLabs/sprout@latest

Homebrew and the Linux packages include shell completions and a man page. For other installs, add completions yourself:

sprout --completion zsh > "${fpath[1]}/_sprout"       # or bash, fish, powershell

With your coding agent

sprout mcp is a Model Context Protocol server, so agents get the map, the graph and impact as tools instead of spending their context on ls -R and grep.

Claude Code, in your project:

claude mcp add sprout -- sprout mcp

Cursor: .cursor/mcp.json in your project, or ~/.cursor/mcp.json for all of them:

{ "mcpServers": { "sprout": { "command": "sprout", "args": ["mcp", "${workspaceFolder}"] } } }

VS Code: .vscode/mcp.json in your project:

{ "servers": { "sprout": { "type": "stdio", "command": "sprout", "args": ["mcp", "${workspaceFolder}"] } } }

Or let Sprout print it with your sprout's full path filled in: sprout mcp --print-config cursor (or vscode, claude-desktop, claude-code).

Claude Desktop: Settings β†’ Developer β†’ Edit Config, which opens ~/Library/Application Support/Claude/claude_desktop_config.json on macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows. Desktop apps don't know your project, and often can't find Homebrew's binaries on their own, so give both in full (which sprout prints the first):

{ "mcpServers": { "sprout": { "command": "/opt/homebrew/bin/sprout", "args": ["mcp", "/path/to/your/project"] } } }
Tool Does
project_map The --ai map, key files included. Agents are told to call it first
reading_order The --entry list
tree A tree of any folder, with optional git status or churn
diff_tree --diff for a revision like main...HEAD
dependents What depends on a file, and why
deps What a file depends on, and why
impact What a change could break, and the tests to run: given files, uncommitted, staged, a range or a commit
context What to know before editing a file: signatures it uses, its users, its tests

Every tool also takes root, the project's absolute path, for when the agent is working in a project other than the folder its client has open. It must be a project folder (one with .git or a manifest like go.mod), not a hidden one, and inside the folder you gave sprout mcp, if you gave one.

Agents are told when each tool beats searching by hand. The server is read-only. Paths and file arguments are confined to the project, symlinks included, git arguments can't carry options, and it never clones.

If it doesn't work

  • No sprout tools show up: restart the client after editing its config. Run sprout mcp in a terminal; it should print MCP server on stdio, root … and wait. "command not found" in the client's MCP log means it can't see your PATH: use the full path from which sprout.
  • The map is of the wrong folder: the server serves the folder you pass it, else the one your client says is open (MCP roots, followed when it changes), else the one it started in. In / or your home folder, whether it started there or the client is open there, it refuses rather than map everything. Start the agent inside the project, pass the project explicitly as in the examples above, or let the agent pass root. When a file isn't found, the error names the folder being served.
  • Stale results: there are none to worry about. Every call reads the disk again, so files your agent just wrote are in the next answer.

tour: get oriented in one command

sprout tour is --entry with context: the README's opening line, the ecosystems and languages, the top-level layout, why each file is on the reading list, and what to run next.

$ sprout tour testdata/tour
Tour of tour

Purpose (README.md excerpt): A small command that prints a greeting.
...
Start here:
  1. README.md β€” project overview (README)
  2. cmd/app/main.go β€” likely entry point (filename convention)
  3. internal/greeting/greeting.go β€” used by 1 file

Next (run from the directory you toured; POSIX shell or PowerShell):
  sprout context './cmd/app/main.go'

--limit N (default 8, up to 50) sets how many reading steps and directories are shown; anything left out is counted. --json prints a stable, versioned object, documented in docs/tour-json.md. It works on a folder or on a repository you haven't cloned (sprout tour github.com/owner/repo). Tour is read-only: it respects ignore rules, skips symlinks, and never runs the commands it suggests. To map a folder named tour, write sprout ./tour.

impact: what a change could break

sprout impact traces a change through the graph: every file that depends on it, directly or through others, and every test that reaches it, with a command to run them: go test for Go, pytest for Python, and vitest, jest, ava or mocha for TypeScript and JavaScript when the project uses one. With no arguments it uses your uncommitted changes; --staged, --diff main...HEAD and --commit HEAD take them from git, or name the files. --all lists every affected file and --json is for scripts and CI.

$ sprout impact pkg/controller/garbagecollector/graph_builder.go   # in kubernetes
Impact of 1 file

  pkg/controller/garbagecollector/graph_builder.go

Affected: 67 files, 8 directly
  cmd/kube-controller-manager/app/controllermanager.go          uses garbagecollector.GraphBuilder, garbagecollector.NewDependencyGraphBuilder
  cmd/kube-controller-manager/app/options/options.go            uses garbagecollector.DefaultIgnoredResources
  pkg/controller/garbagecollector/dump.go                       uses beingDeleted
  pkg/controller/garbagecollector/garbagecollector.go           uses GraphBuilder, NewDependencyGraphBuilder, hasDeleteDependentsFinalizer +2 more
  pkg/controller/garbagecollector/graph.go                      uses beingDeleted
  pkg/controller/garbagecollector/patch.go                      uses monitors
  pkg/controller/storageversionmigrator/storageversionmigrator.go  uses garbagecollector.GraphBuilder, garbagecollector.Monitor
  test/integration/util/util.go                                 uses garbagecollector.DefaultIgnoredResources
  … and 59 more files through them (--all lists them)

Tests: 88 files, 67 Go packages
  go test ./cmd/kube-controller-manager/app ./cmd/kube-controller-manager/app/options ./pkg/controller/garbagecollector ./pkg/controller/storageversionmigrator ./test/e2e ./test/integration/auth ./test/integration/clustertrustbundles ./test/integration/controllermanager ./test/integration/daemonset ./test/integration/disruption ./test/integration/dra ./test/integration/dra/all
  (runs 12 of 67; --all prints the full command)

context: before you edit a file

sprout context FILE is what to know before changing one file, fitted to a token budget (--budget, default 1500): the signatures it actually uses from each dependency, the files that use it and why, the tests that reach it, then what it declares. Agents get it as the context MCP tool.

$ sprout context pkg/controller/garbagecollector/garbagecollector.go --budget 700   # in kubernetes
# pkg/controller/garbagecollector/garbagecollector.go
27 dependencies Β· 5 direct users Β· 60 affected through them Β· 83 tests reach it

## depends on (and what it uses from each)
pkg/controller/controller_ref_manager.go β€” uses c.GenerateDeleteOwnerRefStrategicMergeBytes
  func GenerateDeleteOwnerRefStrategicMergeBytes(dependentUID types.UID, ownerUIDs []types.UID, finalizers ...string) ([]byte, error)
pkg/controller/garbagecollector/errors.go β€” uses restMappingError
  func (r *restMappingError) Error() string
  type restMappingError struct
pkg/controller/garbagecollector/graph.go β€” uses node, objectReference, ownerReferenceCoordinates
  type objectReference struct
  type node struct
  func (n *node) isBeingDeleted() bool
  func (n *node) isObserved() bool
…
## used by
cmd/kube-controller-manager/app/core.go β€” uses garbagecollector.GarbageCollector, garbagecollector.NewComposedGarbageCollector
pkg/controller/garbagecollector/dump.go β€” uses GarbageCollector
pkg/controller/garbagecollector/operations.go β€” uses GarbageCollector, namespacedOwnerOfClusterScopedObjectErr
pkg/controller/garbagecollector/patch.go β€” uses GarbageCollector
test/integration/util/util.go β€” uses garbagecollector.NewGarbageCollector

deps and dependents: what a file touches

sprout deps FILE lists what a file depends on, and sprout dependents FILE what depends on it, tests included. Each line says why: the import, or for Go, the names it actually uses. --depth N follows more hops (-1 for all), --no-tests skips test files, and --json is for scripts.

$ sprout dependents graph.go --depth 2
11 files (6 tests) depend on graph.go

  ai.go              uses Graph
  codegraph.go       uses FileID, Graph, GraphFile +2 more
  entry.go           uses FileID, Graph
  query.go           uses FileID, Graph
  codegraph_test.go  test Β· uses Graph
  graph_test.go      test Β· uses FileID, Graph, GraphFile +1 more
  graphdump_test.go  test Β· uses FileID
  main.go            via ai.go Β· uses AIMap
  ai_test.go         test Β· via ai.go Β· uses estimateTokens
  bench_test.go      test Β· via codegraph.go Β· uses buildGraph
  query_test.go      test Β· via query.go Β· uses queryResult

Go is resolved to the file that declares what's used. Other languages are resolved from their imports: tsconfig paths and workspace packages for TypeScript, real source roots for Python, and crates, use trees and workspace crates for Rust. tools/accuracy checks this against each language's own tooling. To map a folder named deps or dependents, write ./deps.

--ai: context for LLMs

A structure-first map of the project, sized to a token budget (--budget, default 2000). It contains:

  • the README's opening line
  • the detected stack and languages
  • entry points and the config/CI files
  • uncommitted work and the 90-day hotspots
  • the layout, opened breadth-first
  • the key files: the files the rest of the code uses most, with their function and type signatures

It never includes file bodies. Here's the key-files section for sindresorhus/ky:

## key files (most used first)
source/types/options.ts (used by 12): export type SearchParamsInit; export type SearchParamsOption; …
source/core/constants.ts (used by 8): export const supportsRequestStreams; export const supportsAbortController; …
source/errors/KyError.ts (used by 7): export class KyError extends Error
source/types/request.ts (used by 5): export type KyRequest<T = unknown>

Signatures come from Go's own parser. For TypeScript/JavaScript, Python, Rust, Java and Kotlin, Sprout reads declarations and imports line by line. Files are ranked by how many other files import or reference them, and tests don't count.

--entry: where to start reading

$ sprout github.com/charmbracelet/bubbletea --entry
Reading order for bubbletea

  1. README.md                   what the project is
  2. tutorials/basics/main.go    entry point
  3. tutorials/commands/main.go  entry point
  4. tea.go                      used by 25 files
  5. mouse.go                    used by 7 files

A tree that knows what matters

Inside a git repo, .gitignore decides what's shown. Sprout asks git itself, so nested ignores, negations and global excludes all work. Outside git, node_modules, .venv, dist and similar folders are hidden instead. The last line always says how much was left out.

Flag
-L, --depth N Limit depth
--ignore PATTERNS Hide matches, in gitignore syntax: '*.log', 'src/gen/', 'docs/**/*.png', '!keep.log'
--only PATTERNS Show only matching files and prune emptied folders: '*.go', 'web/src/**/*.tsx'
--changed-within AGE Only files modified recently: 30m, 12h, 7d, 2w
--max-files N At most N files per folder, then … 37 more files
--size File sizes and true folder totals, even past --depth
--sort name|size|time Largest or newest first. -r reverses; --dirs-first lists folders first; --si uses powers of 1000
-a, --all Show hidden and ignored entries
--hyperlink Make names clickable in terminals that support links

A .sproutignore in the project applies the same patterns on every run.

--diff: a pull request as a tree

$ sprout --diff main...HEAD -L 1
. main...HEAD
β”œβ”€β”€ .github/  (2 changed)  +13 -28
β”œβ”€β”€ cursed_renderer.go  M  +67 -17
β”œβ”€β”€ examples/  (3 changed)  +5 -5
β”œβ”€β”€ tea.go  M  +45 -20
└── testdata/  (13 changed)  +13 -13

34 files changed, +469 -98

It takes any git revision: main...HEAD, HEAD~3, v1.0..v1.1.

--git and --churn

--git marks M modified, A added, D deleted (shown where the file was), R renamed, ? untracked and U conflicted, and counts changes on folders. --churn draws how many commits touched each path. --since '90 days ago' narrows the window.

Remote repositories

sprout github.com/owner/repo --ai
sprout git@github.com:acme/private.git --churn -L 2

Any git URL, or host/owner/repo shorthand, is cloned into a temporary folder, mapped, and deleted afterwards. Private repos work through your git credentials. A cloned repo's own .sproutrc is ignored.

Config

Put default flags in ~/.config/sprout/config (or $SPROUT_CONFIG), or in a .sproutrc for one project. Use one flag per line:

--depth 3
--hyperlink
--ignore=*.snap,fixtures/

The command line always wins. --no-config skips both files.

Scripting

--json emits the tree, stack and stats, with a schemaVersion. Adding fields isn't a breaking change. Every other flag applies, so sprout --diff main...HEAD --json can feed a PR bot directly.

Sprout's deps, dependents, impact, context and tour commands support --json for machine-readable output with a schemaVersion. The impact command reports affected files, tests and test commands for supported languages through testCommands (Python, TypeScript and JavaScript) and goTestPackages (Go). The context FILE --json command provides file context, while tour --json returns a structured project tour. These outputs can be used in scripts, CI workflows and bots.

For example, run Go tests for packages affected by a branch:

sprout impact --diff origin/main...HEAD --json |
  jq -r '.goTestPackages[]' |
  xargs go test

Example output from sprout dependents graph.go --json, trimmed:

{
  "schemaVersion": 1,
  "command": "dependents",
  "file": "graph.go",
  "depth": 1,
  "results": [
    {
      "path": "ai.go",
      "depth": 1,
      "reason": "uses Graph"
    },
    {
      "path": "codegraph.go",
      "depth": 1,
      "reason": "uses FileID, Graph, GraphFile +2 more"
    }
  ]
}

Speed

Sprout reads only what the output needs and parses sources in parallel. On Kubernetes (31,412 files, Apple M4, warm cache), from the controlled run in the benchmark log:

Command Time
sprout 0.23 s
sprout --json 0.33 s
sprout --entry 0.57 s
sprout --ai 0.72 s

tour costs about what --entry does; impact and context add the tests to the graph (about half a second more on Kubernetes). bench_test.go reproduces the numbers, and the log says exactly how they were measured.

Why not repomix, aider or serena?

They're good tools that solve neighbouring problems:

  • Repomix, code2prompt pack whole files into one prompt. That's right when the model should read everything and it fits. Sprout gives a ranked map (where to start, which files everything depends on, with signatures) in a fixed token budget, and answers questions about the code instead of shipping all of it.
  • Aider's repo map ranks files and symbols much like --ai does, but it lives inside aider. Sprout's map, graph and impact work in any agent over MCP, and in your terminal.
  • Serena gives agents symbol-level navigation and editing through language servers, precise but heavier: a language server per language. Sprout is one binary with nothing to set up; its graph is file-level, built from imports and references, and adds what a language server doesn't: reading order, change impact with tests to run, git hotspots, and repositories you haven't cloned.

Design principles

  • Useful by default. sprout with no flags should usually be enough.
  • Transparent. Anything hidden automatically is counted and can be shown.
  • Humans and machines. Color only on terminals (NO_COLOR respected), plain text in pipes, JSON when asked.
  • Small. One static binary, standard library only. git is needed only for git features.

Contributing

New to open source? Issues labelled good first issue are small, say where to look and how to test, and are a good place to start. CONTRIBUTING.md walks you through it. Questions and ideas: Discussions. Bugs: open an issue. Security problems: see SECURITY.md.

License

MIT

Documentation ΒΆ

The Go Gopher

There is no documentation for this package.

Directories ΒΆ

Path Synopsis
tools
accuracy/truth/gotruth command
Command gotruth is the ground truth for Go, at package level: each file's imports come from go/parser, and an import path maps to the directory of the repository module with the longest matching module path, which is how the go command resolves packages when every module is local.
Command gotruth is the ground truth for Go, at package level: each file's imports come from go/parser, and an import path maps to the directory of the repository module with the longest matching module path, which is how the go command resolves packages when every module is local.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL