reposcan docs

Install methods, every CLI flag, the config.toml reference, and the JSON report format. Written against v1.4.1, with features from the next release marked.

Install

Install script (recommended)

Detects your OS and architecture and puts the latest release binary in a directory on your $PATH. Supports linux/amd64, darwin/amd64 and darwin/arm64. Read the script first.

$ curl -fsSL https://raw.githubusercontent.com/mabd-dev/reposcan/main/install.sh | sh

Two optional environment variables:

VariableDefaultEffect
VERSIONlatestInstall a specific version.
ALIASreposcanName of the installed binary.
$ curl -fsSL https://raw.githubusercontent.com/mabd-dev/reposcan/main/install.sh | VERSION=1.4.1 ALIAS=rs sh

Release binaries

Download an archive for your platform from GitHub releases and put the binary on your $PATH.

go install

$ go install github.com/mabd-dev/reposcan@latest

This puts the binary in $GOPATH/bin (usually ~/go/bin). The install script uses a different directory, so if you switch methods, remove the old binary first with rm "$(which reposcan)"; otherwise whichever comes first on your $PATH wins.

From source

$ git clone https://github.com/mabd-dev/reposcan.git
$ cd reposcan
$ go build -o reposcan .

Usage

# scan your home directory (the default root)
$ reposcan

# several roots
$ reposcan -r ~/Code -r ~/work

# only repos with commits that are not on the remote
$ reposcan -f unpushed

# a JSON report for scripts
$ reposcan -o json

Settings load in three layers, each overriding the one before: built-in defaults, then ~/.config/reposcan/config.toml if it exists, then CLI flags.

CLI flags

Flagconfig.tomlDefaultWhat it does
-r, --root PATHroots$HOMEDirectory to scan. Repeat for more roots.
-d, --dirIgnore GLOBdirIgnoresee configGlob to skip while walking. Repeatable; doublestar patterns such as **/node_modules/** work. Any -d replaces the configured list for that run.
-f, --filter TYPEonlydirtyWhich repos to report: dirty, uncommitted, unpushed, unpulled, stash or all.
-o, --output TYPEoutput.typeinteractiveinteractive opens the TUI, json prints a report, none prints nothing.
--json-output-path DIRoutput.jsonPathunsetAlso write a timestamped JSON report into DIR, creating it if missing.
-w, --max-workers NmaxWorkers8How many repositories are checked concurrently.
--debugdebugfalseWrite a log file to ~/.config/reposcan/logs/.
--no-telemetryno-telemetryfalseTurn off anonymous usage data. See telemetry.

Filters

config.toml

reposcan reads ~/.config/reposcan/config.toml. Every key is optional; anything you leave out keeps its default. A complete example with the defaults spelled out:

version = 1
debug = false
no-telemetry = false

# directories to search for repositories (default: your home directory)
roots = ["~/Code", "~/work"]

# all | dirty | uncommitted | unpushed | unpulled | stash
only = "dirty"

# treat repos whose only local state is a stash as dirty (config only, no flag)
countStashAsDirty = false

maxWorkers = 8

# globs skipped during the walk; setting this replaces the built-in list
dirIgnore = [
  "**/node_modules/**",
  "**/vendor/**",
  "**/.cache/**",
]

[output]
type = "interactive"        # interactive | json | none
jsonPath = ""               # directory for timestamped JSON reports

[tui]
showVCS = true              # VCS column in the table (next release)

Default ignore list

Out of the box reposcan skips dependency folders (node_modules, vendor, .venv, venv, .m2, .gradle, .cargo, target and similar), build output (build, dist, .next, .nuxt), caches (.cache, .local, .pytest_cache), editor folders (.idea, .vscode), and system directories such as /proc, /sys, /tmp, /System, /Library and ~/Library. The full list is in sample/config.toml.

JSON output

-o json prints one report to stdout; --json-output-path writes the same report to a timestamped file. A trimmed example:

{
  "version": 1,
  "repoStates": [
    {
      "id": "4aa059a05b26cd1a",
      "path": "/home/you/Code/api",
      "repo": "api",
      "vcsType": "git",
      "branch": "main",
      "uncommitedFiles": [" M server.go"],
      "remoteStatus": [
        { "remote": "origin", "ahead": 2, "behind": 0 }
      ],
      "stashes": []
    }
  ],
  "totalScannedRepos": 142,
  "generatedAt": "2026-10-07T21:26:03.802613+03:00",
  "warnings": []
}
FieldMeaning
versionReport format version, currently 1.
repoStates[]One entry per repository that matched the filter.
idStable identifier derived from the path.
path, repoAbsolute path and directory name.
vcsTypegit or jj. Added in the next release.
branchCurrent branch (for jj, the current bookmark or change).
uncommitedFiles[]Porcelain-style status lines. The key is spelled this way in the output.
remoteStatus[]remote, ahead, behind. -1 means there is no upstream to compare with. jj entries also carry outgoingCommits.
stashes[]Stash entries.
totalScannedReposEvery repository found, before filtering.
generatedAtRFC 3339 timestamp.
warnings[]Non-fatal problems hit during the scan.

Git worktrees

Besides ordinary .git directories, reposcan recognises the .git file that linked worktrees and submodules use (a file containing a gitdir: pointer), and reports each worktree as its own row. Linked worktrees share their main checkout's stash list, so a stash shows up on each of them.

jj (Jujutsu) next release

jj support is merged but not in v1.4.1; build from source to use it now. reposcan detects .jj directories in the same walk as Git and collects read-only state: name, current bookmark or change, uncommitted files, outgoing commits for tracked bookmarks, and incoming counts from already-fetched remote bookmarks.

Current limits:

Updating

Re-run the install script; it always installs the latest release. From the next release on, reposcan update checks GitHub and replaces the binary in place. If you installed under a custom name, pass it with reposcan update --alias rs.

Telemetry

reposcan sends anonymous usage data to Mixpanel: OS, CPU architecture, tool version, whether it runs in CI, and the flags used (filter, output format, repo count). No usernames, tokens or file paths. You see a one-time notice on first run. Turn it off with --no-telemetry or no-telemetry = true in config.toml.