# How it works (/docs/how-it-works)

Where the repository list comes from, how it is cached, what runs on your machine and what counts against GitHub's rate limits.

## Authentication [#authentication]

gh-select has no login of its own. It reads the token for your default host from the GitHub CLI and uses it for the REST and GraphQL APIs. The token is read once per run. When `gh` has no token, the program exits with `could not authenticate with GitHub (run gh auth login)`.

Deleting repositories is the only feature that needs an extra scope. See [Deleting repositories](/docs/guides/deleting-repositories).

## The repository list [#the-repository-list]

The list holds every repository you own, belong to through an organization, or collaborate on, de-duplicated and ordered by recent activity. Your repositories and your stars load as parallel REST pages. Fork parents and languages, which the REST listing leaves out, come from one small GraphQL lookup. Around 300 repositories load in about a second.

Each entry carries its visibility, language, star count, last push, license, disk size, fork parent and archived state. Those fields drive the columns, the details block and the [filter tokens](/docs/reference/filter-tokens).

## Caching [#caching]

The list is cached on disk and follows a stale-while-revalidate rule:

1. With a cache present, the list renders immediately from it.
2. When the cache is older than `GH_SELECT_CACHE_TTL` seconds (1800 by default), a refresh runs in the background and the list updates when it finishes.
3. With no cache, the program fetches first and prints `Loading repositories…`, so the screen is never empty.

`-n` or `--no-cache` skips the cache and fetches fresh data. `gh select refresh` refetches and exits, which suits cron jobs. Starred repositories have their own cache, shown instantly and refreshed once per session.

The cache files are versioned. Upgrading to a release that adds repository fields refetches once. See [files and paths](/docs/reference/files-and-paths) for the names and the directory.

## Local clones [#local-clones]

gh-select finds repositories you already cloned and tags them `local`. The scan runs in the background on every start and is cached in `locals.json` for the next one, so the tags appear without waiting.

- It searches `GH_SELECT_SCAN_DIRS` first, then the clone directory, the current directory and your home directory.
- A repository is matched by its git remote, so a renamed folder is still recognized. HTTPS, SSH and `ssh://` remotes all work.
- Git worktrees and submodules count.
- Dependency and cache folders such as `node_modules`, `vendor`, `target`, `dist`, `build`, `venv`, `Library` and `snap` are skipped, and so are hidden folders other than `.config` and `.dotfiles`.
- One scan reads at most 40000 directories, and a folder with more than 4096 entries is treated as data and skipped.
- When a repository is cloned twice, the most recently used copy wins.

## Rate limits [#rate-limits]

GitHub gives each account separate budgets for search, core REST, GraphQL and code search. Other tools using your `gh` login draw from the same budgets.

| Bucket        | Window   | Used by                                    |
| ------------- | -------- | ------------------------------------------ |
| `search`      | 1 minute | GitHub search scope                        |
| `core`        | 1 hour   | Listing, trees, files, releases, downloads |
| `graphql`     | 1 hour   | Fork parents and languages                 |
| `code_search` | 1 minute | Shown for completeness                     |

GitHub search waits until you pause typing for 350 ms before it fires, and fetches a single page of 30 results per query. `gh select limits` and the `?` overlay show usage, how far each window has run, time to reset, and how soon the current pace would empty a bucket. Reading the limits does not count against any of them.

## Cloning, saving and downloading [#cloning-saving-and-downloading]

- A clone runs `git clone` through your own `git`, so your SSH keys and credential helpers apply. The URL is `https://github.com/OWNER/REPO.git`.
- A partial clone runs `git clone --filter=blob:none --sparse`, then a sparse checkout of the marked paths. Folders alone use cone mode. Individual files switch to non-cone patterns anchored at the repository root. Blobs are fetched when needed.
- Saving files and downloading release assets use the GitHub API directly and need no git.
- Opening a URL uses `open` on macOS, `rundll32` on Windows, and `xdg-open` or `wslview` elsewhere. Copying uses `pbcopy`, `clip.exe`, `wl-copy`, `xclip` or `xsel`, whichever exists.

## What is written to disk [#what-is-written-to-disk]

Only the cache, the saved theme and any files you ask for. gh-select never changes your repositories' contents, and deleting a repository on GitHub never removes a local clone.
