Check that a GitHub issue is really free before you start working on it.
gh-claimcheck is a GitHub CLI extension for open source contributors. Give it an issue, and it tells you if someone already has an open pull request for it, if someone claimed it in the comments, if the project moved somewhere else, or if maintainers don't merge outside PRs. You get a clear GO, CAUTION or SKIP in a few seconds, so you don't spend an evening on a fix that turns out to be a duplicate.
It can also find open, unassigned issues with no linked PR in the languages and projects you care about, or in the libraries your own project depends on, and check each one for you.
$ gh claimcheck date-fns/tz#80
date-fns/tz#80 tzOffset: wrong sign for offsets between -01:00 and 00:00
https://github.com/date-fns/tz/issues/80
! An open PR looks like the same fix
date-fns/date-fns#4314 by @contactjawad: Fix tzOffset returning the wrong sign for sub-hour western offsets
https://github.com/date-fns/date-fns/pull/4314
! An open PR looks like the same fix
date-fns/date-fns#4279 by @Kropiunig: fix(tz): correct tzOffset sign for negative offsets of less than an...
https://github.com/date-fns/date-fns/pull/4279
! Project has moved to date-fns/date-fns
Pull requests probably belong in the new home. Its pull requests were searched too.
! The last outside PR was merged 14 months ago
6 of the last 6 merged PRs came from 6 outside contributors. Reviews may be slow, or the project may be quiet.
✓ Issue is open
✓ Nobody is assigned
· 3 PRs share keywords with the title
date-fns/date-fns#4396 (open), date-fns/date-fns#4335 (open), date-fns/date-fns#4356 (open). Probably different fixes, but skim them.
CAUTION An open PR looks like the same fix
Look into the points above, and ask on the issue before you start.None of those PRs mention the issue, and they live in a different repository, so the issue page itself shows nothing. That's exactly the case claimcheck is built to catch. (Output trimmed a little; the README notice line is shortened.)
1. Install the GitHub CLI (skip if gh --version already works):
| System | Command |
|---|---|
| macOS | brew install gh |
| Windows | winget install --id GitHub.cli |
| Debian, Ubuntu | sudo apt install gh (or see the official instructions for the latest version) |
| Fedora | sudo dnf install gh |
| Other | see cli.github.com |
2. Log in to GitHub. claimcheck uses this login to read issues and pull requests; it never writes anything.
gh auth loginChoose GitHub.com, then HTTPS, then Login with a web browser, and paste the one-time code it shows. Check it worked with gh auth status.
3. Install claimcheck:
gh extension install RagedPanda/gh-claimcheck4. Try it:
gh claimcheck --help
gh claimcheck find --good-first-issue --limit 5Upgrade later with gh extension upgrade claimcheck. Prebuilt binaries are provided for macOS, Linux and Windows; you don't need Go.
Something went wrong?
| Message | Fix |
|---|---|
command not found: gh or gh: command not found |
Step 1: install the GitHub CLI, then open a new terminal. |
claimcheck: not logged in to GitHub; run gh auth login |
Step 2: run gh auth login. If you are logged in, your login may have expired: run gh auth refresh. |
unknown command "claimcheck" for "gh" |
Step 3: install the extension. |
rate limit in the error |
Wait a few minutes. GitHub limits how many searches an account can run per minute. |
-
Find an issue you'd like to fix, or let claimcheck find some:
gh claimcheck find --good-first-issue --lang python
-
Check the one you picked. A URL,
owner/repo#123, or just123inside a clone all work:gh claimcheck https://github.com/owner/repo/issues/123
-
Read the verdict:
Verdict Meaning What to do GO Nobody seems to be on it. Comment on the issue that you're working on it, then open a PR. CAUTION Something needs a look: a PR that may be the same fix, an old claim, a maintainer who pushed back, a project that rarely merges outside PRs. Read the !lines. Ask on the issue before you start.SKIP Someone already has an open or merged PR for it, someone claimed it recently, it's assigned, closed, locked or archived. Pick another issue. -
Before you open your PR, read the project's contributing guide. claimcheck tells you where it is and whether the project has rules about AI-written code.
| Check | Why it matters |
|---|---|
| Linked and referencing pull requests (open, draft, merged, closed) | The most common way to waste effort is fixing something that already has a PR. |
| PRs with a similar title, ranked by how closely they match | Many PRs never mention the issue number. |
| Project moved (README notice like "moved to the monorepo") | The fix and the other PRs are often in the new repository; it is searched too. |
Claims in comments ("I'd like to work on this", /assign, "I've opened a PR") |
Someone may be on it without being assigned. Recent claims block; old ones only warn. |
| Offers in the issue itself ("Yes" to "Are you willing to submit a PR?", "Happy to open a PR") | The reporter may already be writing the fix, often waiting for a maintainer to agree first. Warns. |
| Assignees, closed, locked, archived | The basics, all in one place. |
| Maintainer pushback ("working as intended", "won't fix", "duplicate of") | A PR for an issue maintainers rejected won't be merged. |
Blocking labels (needs repro, wontfix, blocked, needs discussion...) and welcoming ones (good first issue, help wanted) |
Labels say whether a PR is wanted right now. |
| Outside merges: who wrote the last 40 merged PRs, and when | Some projects only merge their own team's work, or haven't merged anything in a year. |
AI policy in CONTRIBUTING.md, AI_POLICY.md, AGENTS.md |
Some projects ban or require disclosure of AI-assisted PRs. |
| Contributing guide, PR template, CLA | So you know what the PR needs before you write it. |
Your own claims, assignments and PRs never count against you. If you're already on an issue, it says so.
gh claimcheck find searches for open issues with no assignee, no linked PR, few comments and a recent creation date, in non-archived repositories. Add --check to run the full check on every result.
# Beginner-friendly issues in Go
gh claimcheck find --good-first-issue --lang go
# Recent issues in popular TypeScript projects that came out GO
gh claimcheck find --lang typescript --min-stars 1000 --check --go-only
# Everything new in one organisation in the last two weeks
gh claimcheck find --org vitejs --days 14 --check
# Search words, inside one repository, with no comments yet
gh claimcheck find "timezone" --repo date-fns/date-fns --max-comments 0$ gh claimcheck find --lang typescript --min-stars 1000 --days 14 --check --limit 6 # trimmed
GO NativeScript/NativeScript#11566 ★25.7k 0c today @nativescript/vite: link check rejects valid aliased default exports
CAUTION mebjas/html5-qrcode#1076 ★6.2k 0c today Bug Iphone14
GO ranxianglei/billion-context#4307 ★2.4k 0c today Compression calls with lost ACKs are permanently stuck in context: client-sid...
CAUTION anomalyco/opencode#58123 ★220.0k 1c today Stuck on a single message from few minutes| Flag | Default | Meaning |
|---|---|---|
-R, --repo owner/repo |
Search one repository (repeatable, or comma separated) | |
--org name |
Search an organisation or user (repeatable) | |
-l, --lang language |
Only this language (repeatable) | |
--label name |
Require a label (repeatable) | |
--good-first-issue, --help-wanted |
Shortcuts for those labels | |
--days n |
60 |
Created in the last n days; 0 for any age |
--max-comments n |
3 |
At most n comments; -1 for any |
-s, --min-stars n |
Only repositories with at least n stars | |
-L, --limit n |
20 |
Number of results, 1 to 100 |
-c, --check |
Run the full check on each result | |
--go-only |
Show only results that come out GO (implies --check) |
|
--json |
JSON output |
The best first contribution is often to a library you already use: you know what it does, and you can test the fix in your own project. gh claimcheck deps reads your project's manifests and lock files, finds each library's GitHub repository, and searches them all for open, unclaimed issues. Lock files add the libraries your libraries use.
# The project in the current directory
gh claimcheck deps
# Another directory; only the libraries you list yourself, each checked
gh claimcheck deps ~/code/my-app --direct-only --check
# Beginner-friendly issues, skipping test and build tools
gh claimcheck deps --good-first-issue --no-dev
# Just show which repositories it would search
gh claimcheck deps --list$ gh claimcheck deps --days 0 --max-comments -1 -L 4 # in this repository
cli/go-gh#220 via github.com/cli/go-gh/v2 ★443 0c 171d `(*GraphQLClient).DoWithContext` should expose response headers such as `x-ra...
cli/go-gh#212 via github.com/cli/go-gh/v2 ★443 0c 251d Add option for env var to bypass certificate checks
cli/go-gh#189 via github.com/cli/go-gh/v2 ★443 2c 556d Migrate from `go-yaml/yaml` to `goccy/go-yaml`
cli/go-gh#167 via github.com/cli/go-gh/v2 ★443 1c 870d Support passing httptest URLs in api.ClientOptionsIssues in your direct dependencies come first, then the newest. It looks in every directory under the one you give it, skipping node_modules, vendor, build output and virtual environments, so monorepos work.
| Ecosystem | Files it reads | Repository looked up on |
|---|---|---|
| JavaScript, TypeScript | package.json, package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml, bun.lock |
npm |
| Deno | deno.json, deno.jsonc, deno.lock (jsr: and npm: imports) |
JSR, npm |
| Python | requirements*.txt, requirements*.in, pyproject.toml (PEP 621, Poetry, dependency groups), Pipfile, poetry.lock, uv.lock, setup.py, setup.cfg |
PyPI |
| Conda | environment.yml (its pip: section goes to PyPI) |
conda-forge |
| Go | go.mod |
the module path, or its go-import tag |
| Rust | Cargo.toml, Cargo.lock |
crates.io |
| Android, Kotlin, Java | build.gradle, build.gradle.kts, libs.versions.toml, pom.xml |
Maven Central, via deps.dev |
| Scala | *.sbt |
Maven Central, via deps.dev |
| Clojure | deps.edn, project.clj |
Clojars, then Maven Central |
| C, C++ | vcpkg.json, conanfile.txt, conanfile.py, conan.lock |
vcpkg ports, ConanCenter recipes |
| Ruby | Gemfile, Gemfile.lock, gems.rb, gems.locked |
RubyGems |
| PHP | composer.json, composer.lock |
Packagist |
| Dart, Flutter | pubspec.yaml, pubspec.lock |
pub.dev |
| Swift, iOS | Package.swift, Package.resolved, Podfile.lock, Cartfile, Cartfile.private, Cartfile.resolved |
the package URL, CocoaPods |
| Elixir, Erlang | mix.exs, mix.lock, rebar.config, rebar.lock |
Hex |
| .NET | *.csproj, *.fsproj, *.vbproj, Directory.Packages.props, packages.lock.json |
NuGet, via deps.dev |
| GitHub Actions | .github/workflows/*.yml, action.yml |
the action's repository (counted as dev) |
| Docker | Dockerfile, Containerfile, compose.yaml, docker-compose.yml |
a built-in list of images, and ghcr.io/owner/... |
Git dependencies on GitHub (in mix.exs, rebar.config, deps.edn and Carthage files) are searched directly. The Docker list covers the databases, caches, queues and runtimes projects usually run, such as redis, rabbitmq, elasticsearch, clickhouse, nginx, node and golang. Some well-known projects (PostgreSQL, MySQL, MongoDB, MariaDB) take bug reports outside GitHub, so they are not searched.
It takes the same issue flags as find (--label, --good-first-issue, --help-wanted, --days, --max-comments, --min-stars, --limit, --check, --go-only, --json), plus:
| Flag | Meaning |
|---|---|
--direct-only |
Only libraries your manifests list, not their dependencies |
--no-dev |
Skip development and test dependencies |
--list |
Print each library and its repository, without searching |
Libraries that aren't on GitHub (private packages, AndroidX, projects hosted elsewhere) are skipped. Registry answers are cached for a week, so running it again on the same project is quick.
Check several issues at once, in parallel:
gh claimcheck cli/cli#14703 vitest-dev/eslint-plugin-vitest#980 date-fns/tz#80 --briefSKIP cli/cli#14703 An open PR already references it
GO vitest-dev/eslint-plugin-vitest#980 You are already on it
CAUTION date-fns/tz#80 An open PR looks like the same fixExit status. With --exit-status, the exit code tells you the worst verdict: 0 all GO, 3 any CAUTION, 2 any SKIP, 1 an error. Without it, the code is 0 unless something failed.
gh claimcheck "$issue" --exit-status >/dev/null && echo "free to take"JSON. --json prints every finding with its level (block, warn, pass, info), title, detail and URL. It works with jq:
# Only the issues that are GO
gh claimcheck find --lang rust --check --json | jq -r '.[] | select(.report.verdict == "GO") | .url'
# Why was an issue skipped?
gh claimcheck owner/repo#42 --json | jq -r '.[0].findings[] | select(.level == "block") | .title'Default repository. Inside a clone, bare numbers (123, #123) use that repository. Use -R owner/repo or the GH_REPO environment variable to choose another.
Colour follows the same rules as gh: off when output is piped, and controlled by NO_COLOR, CLICOLOR and CLICOLOR_FORCE.
- Read-only. It never comments, assigns, forks or opens anything. It uses the token from your
ghlogin, so it sees the same repositories you can. - Your code stays local.
depsreads manifest and lock files on your machine and only sends package names to their public registries (npm, PyPI, crates.io and so on) to find each repository. Nothing else is uploaded. - Light on rate limits. One GraphQL query per issue gets the issue, comments, linked PRs, cross-references, community files and recent merges. One or two searches look for similar PR titles. Checks run three at a time.
- Heuristics, not certainty. Claim and pushback detection read plain English comments. A CAUTION means "go and look", not "don't". When in doubt, ask on the issue; maintainers almost always prefer that.
Is it the same as the "linked pull requests" panel on the issue? No. That panel only shows PRs that use a closing keyword. claimcheck also finds PRs that mention the issue, PRs with a similar title that never mention it, PRs in the repository the project moved to, and claims that only exist as comments.
Can I use it on private repositories?
Yes, any repository your gh login can read.
Does it work with GitHub Enterprise?
It uses your gh host settings, so set GH_HOST for an Enterprise server.
It flagged a PR that's not related. Title matching is fuzzy. Only close matches are warnings; the rest are grouped in one "share keywords" line. Please open an issue with the example so the matching can improve.
Issues and pull requests are welcome. The checks are plain functions over plain data, so most changes need no network:
go test ./...internal/check: the rules and verdicts (pure; start here)internal/text: comment and README parsing (claims, pushback, AI policy, moved notices, title similarity)internal/github: the only package that talks to the APIinternal/render: terminal outputinternal/manifest: manifest and lock file parsers (pure; add a new format here)internal/registry: package to GitHub repository lookup
Please run gh claimcheck on the issue first. It's only fair.