Skip to Content
SimulatorsGitHubIssue and pull request search

Simulators

Issue and pull request search

GET /search/issues and the GraphQL search query both search the issues and pull requests the scenario holds, through one grammar. gh pr list --search and gh issue list --search send the GraphQL one. Search a repository’s pull requests by state, draft flag, label, author or date:

H='Authorization: Bearer ghp_anything'
curl -s -G "$RYSTIC_URL/search/issues" -H "$H" --data-urlencode 'q=repo:tb-owner/tb-repo is:pr is:open' | jq -c '{total_count, numbers: [.items[].number]}'
# -> {"total_count":4,"numbers":[44,43,42,41]}
curl -s -G "$RYSTIC_URL/search/issues" -H "$H" --data-urlencode 'q=repo:tb-owner/tb-repo is:pr draft:true' | jq -c '{total_count, numbers: [.items[].number]}'
# -> {"total_count":1,"numbers":[43]}
curl -s -G "$RYSTIC_URL/search/issues" -H "$H" --data-urlencode 'q=repo:tb-owner/tb-repo is:pr label:bug' | jq -c '{total_count, numbers: [.items[].number]}'
# -> {"total_count":1,"numbers":[41]}
curl -s -G "$RYSTIC_URL/search/issues" -H "$H" --data-urlencode 'q=repo:tb-owner/tb-repo retry created:2026-01-01..2026-01-31' | jq -c '{total_count, numbers: [.items[].number]}'
# -> {"total_count":1,"numbers":[42]}
curl -s -G "$RYSTIC_URL/search/issues" -H "$H" --data-urlencode 'q=repo:tb-owner/tb-repo is:pr created:garbage' -o /dev/null -w '%{http_code}\n'
# -> 422
curl -s -G "$RYSTIC_URL/search/issues" -H "$H" --data-urlencode 'q=repo:tb-owner/tb-repo is:pr reactions:>1' -D - -o /dev/null | grep -i x-rystic-marker
# -> X-Rystic-Marker: unmodeled_guard; iv=iv_op_get_search_issues; guard=g_qualifiers_modelled

Qualifiers

repo:, user:, org: and owner: scope the query, and a query naming none matches nothing. The grammar reads these other qualifiers:

KindQualifiers
Family and stateis:pr, is:pull-request, is:issue, type:, state:, reason:completed, reason:"not planned", draft:true, draft:false, archived:, language: and is: with open, closed, merged, unmerged, draft, locked, unlocked, public or private
Peopleauthor:, assignee:, review-requested:, reviewed-by:, commenter:, mentions:, involves:, each with @me as the caller
Contentlabel:, milestone:, no:label, no:assignee, no:milestone, head: and base: (a branch-name prefix), comments: (a count or range), review:none, review:approved, review:changes_requested
Datescreated:, updated:, closed:, merged:

A date is YYYY-MM-DD, covering its whole UTC day, or an ISO 8601 timestamp. a..b is inclusive, and * leaves an end open. >=, >, <= and < bound one side.

Combining

Terms AND, and - negates any of them. label:a,b ORs its labels. The advanced syntax is what gh sends as type: ISSUE_ADVANCED, and what REST takes with advanced_search=true. The two syntaxes read a query differently:

QueryDefault syntaxAdvanced syntax
a repeated author: or other person qualifierORsANDs
a repeated label:ANDsANDs
AND and ORjoin only free textoperators
parenthesesa bare one matches nothingoperators

Under the advanced syntax, -( … ) matches nothing.

Free text

Words match title, body and comments, case-insensitively, or the fields in:title, in:body and in:comments name. A word in the record also matches the query word one suffix shorter, so fix finds “fixes” and “fixed”, but fixes does not find “fix” and there is no prefix match. A quoted phrase matches its words in order. A key the grammar does not know, like foo:bar, is text.

Differs from GitHub: free-text matches come within a few pull requests of GitHub’s over the imported scenario.

Refusals

Over REST, an unrecognized date, a login or repository the scenario does not hold or operators with no text return GitHub’s 422. Over GraphQL each matches nothing.

Differs from GitHub: a qualifier GitHub accepts that the simulator cannot evaluate is refused rather than ignored. Such qualifiers include review:required, reactions:, project: and linked:.

OverThe refusal
REST501, with X-Rystic-Marker: unmodeled_guard; iv=iv_op_get_search_issues; guard=g_qualifiers_modelled and GitHub’s error envelope (message, documentation_url, status). The body does not name the qualifier.
GraphQLan error naming g_qualifiers_modelled, not the qualifier

Results

total_count and issueCount count every match. Over REST, per_page (at most 100) and page window the items, with GitHub’s Link header. sort and order, or an in-query sort:created-asc, order them, newest first by default. A pull request’s item carries draft and its own node_id.

Differs from GitHub: a write is searchable at once. GitHub’s index lags by seconds.

Differs from GitHub: closed: and comments: follow the record. GitHub’s index disagrees with its own records: closed: misses pull requests closed in bulk, and comments: undercounts.

Other search types

Differs from GitHub: code and commit search (GET /search/code and GET /search/commits) are not served, and will not be. REST returns GitHub’s 404 Not Found, and GraphQL undefinedField.

Differs from GitHub: GraphQL search with a type other than ISSUE or ISSUE_ADVANCED is refused with an error naming g_search_type_served. That covers ISSUE_SEMANTIC, ISSUE_HYBRID, DISCUSSION, REPOSITORY and USER.

Package and wiki search are not served.

Last updated on