An interactive CLI (powered by Bun) to search GitHub code across an organization, with per-repository result aggregation, keyboard navigation, and fine-grained extract selection.
- Bun ≥ 1.0
- A GitHub token with the
reposcope (for private repos) orpublic_repo
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxcurl -fsSL https://raw.githubusercontent.com/fulll/github-code-search/main/install.sh | bashThe script automatically detects your OS (Linux, macOS) and architecture (x64, arm64) and installs the right pre-compiled binary from the latest release to /usr/local/bin.
To install a specific version or to a custom directory:
INSTALL_DIR=~/.local/bin VERSION=v1.0.6 \
curl -fsSL https://raw.githubusercontent.com/fulll/github-code-search/main/install.sh | bashFrom source (requires Bun ≥ 1.0)
git clone https://github.com/fulll/github-code-search
cd github-code-search
bun install
bun run build.ts
# → produces dist/github-code-searchgithub-code-search <query> --org <org> [options] # default (backward-compat)
github-code-search query <query> --org <org> [options]
github-code-search upgrade
| Command | Description |
|---|---|
<query> / query <query> |
Search GitHub code (default command) |
upgrade |
Check for a new release and auto-upgrade the binary |
| Option | Required | Description |
|---|---|---|
--org <org> |
✅ | GitHub organization to search in |
--exclude-repositories <repos> |
❌ | Comma-separated list of repos to exclude. Short form (without org prefix) accepted: repoA,repoB |
--exclude-extracts <refs> |
❌ | Extracts to exclude. Short format: repoA:src/foo.ts:0,repoB:lib/bar.ts:1 |
--no-interactive |
❌ | Disable interactive mode (equivalent to CI=true) |
--format <format> |
❌ | Output format: markdown (default) or json |
--output-type <type> |
❌ | Output type: repo-and-matches (default) or repo-only |
--include-archived |
❌ | Include archived repositories in results (default: false) |
--group-by-team-prefix <pfxs> |
❌ | Comma-separated team-name prefixes to group repos by GitHub team (e.g. squad-,chapter-) |
The interactive mode is the main advantage of this script over the GitHub Code Search web UI:
- Per-repository aggregation: results are grouped by repo rather than shown as a flat list.
- Fold/unfold: collapse a repo to hide its extracts and focus on others.
- Fine-grained selection: pick exactly which repos and extracts you care about.
- Structured output: on confirmation, you get a clean list with Markdown links to the selected extracts.
- Replay command: a command line is automatically generated to reproduce the exact same selection without the UI (useful for CI or documentation).
| Key | Action |
|---|---|
↑ / ↓ |
Navigate between repos and extracts |
← |
Fold the repo under the cursor |
→ |
Unfold the repo under the cursor |
Space |
Select / deselect the current repo or extract |
a |
Select all (on a repo row: all repos+extracts; on an extract row: all extracts in that repo). Respects the active file-path filter. |
n |
Select none (same context rules as a). Respects the active file-path filter. |
f |
Open the filter bar — type a path substring to show only matching files |
r |
Reset the active filter and show all repos/extracts again |
h / ? |
Toggle the help overlay (shows all key bindings) |
Enter |
Confirm and print selected results (also closes the help overlay) |
q / Ctrl+C |
Quit without printing results |
Press f to enter filter mode. A filter bar appears at the top of the results:
🔍 Filter: src/ ▌ Enter confirm · Esc cancel
Type any path substring (case-insensitive). As you type, the view updates live. Press Enter to confirm the filter or Esc to cancel without applying it.
When a filter is active, a stats line replaces the input bar:
🔍 filter: src/ 3 matches in 2 repos shown · 4 hidden in 1 repo r to reset
The a and n keys operate only on the currently visible (filtered) repos and extracts. Press r to clear the filter.
- Selecting a repo (via
Spaceon the repo row): cascades the selection/deselection to all its extracts. - Selecting an extract individually: if at least one extract remains selected, the parent repo stays selected.
GitHub Code Search: useFeatureFlag in fulll
3 repos · 4 files
← / → fold/unfold ↑ / ↓ navigate spc select a all n none f filter h help ↵ confirm q quit
▶ ◉ fulll/billing-api (3 extracts)
▼ ◉ fulll/auth-service (2 extracts) ← unfolded repo
◉ src/middlewares/featureFlags.ts
…const flag = useFeatureFlag('new-onboarding'); if (!flag) return next();…
◉ tests/unit/featureFlags.test.ts
…expect(useFeatureFlag('new-onboarding')).toBe(true);…
▶ ○ fulll/legacy-monolith (1 extract) ← deselected repo
▶ ◉ fulll/frontend-app (5 extracts)
With an active filter (after pressing f and typing src):
GitHub Code Search: useFeatureFlag in fulll
3 repos · 11 matches
2 repos · 5 matches selected
🔍 filter: src/ 2 matches in 1 repo shown · 9 hidden in 2 repos r to reset
← / → fold/unfold ↑ / ↓ navigate spc select a all n none f filter h help ↵ confirm q quit
▼ ◉ fulll/auth-service (2 extracts)
◉ src/middlewares/featureFlags.ts
…const flag = useFeatureFlag('new-onboarding'); if (!flag) return next();…
After pressing Enter:
3 repos · 6 files · 7 matches selected
- fulll/auth-service (2 matches)
- fulll/billing-api
- fulll/frontend-app
replay command
github-code-search "useFeatureFlag" --org fulll --no-interactive \
--exclude-repositories legacy-monolithNon-interactive mode is useful in three cases:
- Continuous integration: no TTY is available in a GitHub Actions pipeline or similar environment.
- Reproducibility: after an interactive session, the generated replay command lets you re-run the exact same search with the same exclusions, without going through the UI again.
- Scripting: combine the output with other tools (
grep,jq, shell scripts…).
Three equivalent ways:
# 1. Via the standard CI environment variable
CI=true github-code-search "useFeatureFlag" --org fulll
# 2. Via the explicit flag
github-code-search "useFeatureFlag" --org fulll --no-interactive
# 3. In a GitHub Actions pipeline (CI=true is set automatically)
- run: github-code-search "useFeatureFlag" --org fulll
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}$ CI=true github-code-search "useFeatureFlag" --org fulll3 repos · 5 matches selected
- fulll/auth-service
- fulll/billing-api
- fulll/frontend-app
replay command
github-code-search "useFeatureFlag" --org fulll --no-interactiveExcludes entire repos from the results. The org prefix is optional.
# Short form (recommended)
github-code-search "useFeatureFlag" --org fulll \
--exclude-repositories legacy-monolith,archived-app
# Long form (also accepted)
github-code-search "useFeatureFlag" --org fulll \
--exclude-repositories fulll/legacy-monolith,fulll/archived-appExcludes individual extracts. The format is repoName:path/to/file:matchIndex.
The org prefix is optional. The index corresponds to the position of the extract in the API results for that file.
# Exclude extract 0 of src/flags.ts in billing-api
github-code-search "useFeatureFlag" --org fulll \
--exclude-extracts billing-api:src/flags.ts:0
# Exclude multiple extracts
github-code-search "useFeatureFlag" --org fulll \
--exclude-extracts billing-api:src/flags.ts:0,auth-service:tests/unit/featureFlags.test.ts:1
# Long form (also accepted)
github-code-search "useFeatureFlag" --org fulll \
--exclude-extracts fulll/billing-api:src/flags.ts:01. Initial interactive session to explore results:
github-code-search "useFeatureFlag" --org fulllYou navigate, deselect
legacy-monolith, deselect the test extract inauth-service, then press Enter.
2. Output + replay command:
2 repos · 3 matches selected
- fulll/auth-service
- fulll/billing-api
- fulll/frontend-app
replay command
github-code-search "useFeatureFlag" --org fulll --no-interactive \
--exclude-repositories legacy-monolith \
--exclude-extracts auth-service:tests/unit/featureFlags.test.ts:03. Replay without UI (CI, scripting, documentation):
github-code-search "useFeatureFlag" --org fulll --no-interactive \
--exclude-repositories legacy-monolith \
--exclude-extracts auth-service:tests/unit/featureFlags.test.ts:0The header and output summary distinguish two levels of granularity:
| Label | Meaning |
|---|---|
| files | Number of unique file paths across all repos (e.g. src/config.ts present in 3 repos counts as 1 file) |
| matches | Total (repo, file) pairs — i.e. the usual per-repo extract count |
49 repos · 112 files · 234 matches
The matches segment is hidden when it equals files (i.e. every file appears in exactly one repo, which is the common case). It appears automatically as soon as a file path is shared across repos.
When a partial selection is active, both counts show their selected values:
49 repos (47 selected) · 112 files (109 selected) · 234 matches (231 selected)
Group result repositories by their GitHub team membership, using one or more team-name prefixes:
github-code-search "useFeatureFlag" --org fulll \
--group-by-team-prefix squad-,chapter-The option accepts a comma-separated list of prefixes. The tool fetches all org teams matching any of those prefixes, maps each repo to its teams, then applies the following grouping algorithm:
- First prefix (
squad-)- Repos belonging to exactly 1 squad-* team → one section per team, sorted alphabetically.
- Repos belonging to 2 squad-* teams → one section per team *combination*, sorted alphabetically.
- Repos belonging to 3+ squad-* teams → same, in ascending combination-size order.
- Next prefix (
chapter-) — applied to repos that were not assigned in the previous step, using the same rules. - Repos matching no prefix are collected into an
othersection at the end.
4 repos · 5 files · 6 matches selected
## squad-backend
- **fulll/billing-api** (3 matches)
- [src/flags.ts:3:14](https://github.com/fulll/billing-api/blob/main/src/flags.ts#L3)
## squad-frontend
- **fulll/auth-service** (2 matches)
- [src/middlewares/featureFlags.ts:2:19](...)
## squad-frontend + squad-mobile
- **fulll/frontend-app** (1 match)
- [src/hooks/useFeatureFlag.ts:1:1](...)
## other
- **fulll/legacy-monolith** (1 match)
- [src/legacy.js:5:1](...)
In interactive mode each team section appears as a separator line between the corresponding repo rows:
── squad-frontend
▶ ◉ fulll/auth-service (2 matches)
── squad-mobile
▶ ◉ fulll/frontend-app (1 match)
── other
▶ ◉ fulll/legacy-monolith (1 match)
Navigation (↑ / ↓) automatically skips section header rows.
Fetching team membership requires the token to have the read:org (or
admin:org) scope in addition to repo / public_repo.
- The GitHub Code Search API is capped at 1,000 results per query and 10 requests/minute without authentication (30/min with a token).
- Results may differ slightly between calls due to GitHub's indexing.
- An extract's index (
--exclude-extracts) is relative to the order returned by the API: it may change if GitHub re-indexes the repository between calls. For greater stability, prefer whole-repository exclusions (--exclude-repositories) when possible.
Pass --format json (or -format json in CI mode) to get machine-readable output:
CI=true github-code-search "useFeatureFlag" --org fulll --format json{
"query": "useFeatureFlag",
"org": "fulll",
"selection": { "repos": 1, "matches": 1 },
"results": [
{
"repo": "fulll/auth-service",
"matches": [
{
"path": "src/middlewares/featureFlags.ts",
"url": "https://github.com/...",
"line": 2,
"col": 19
}
]
}
],
"replayCommand": "# Replay:\ngithub-code-search \"useFeatureFlag\" --org fulll --no-interactive"
}The interactive mode also respects --format json: pressing Enter will output the JSON payload.