---
name: github-issue-search
description: |
  Searches GitHub issues and pull requests via the GitHub REST Search API using the `q` query language
  (repository scope, state, labels, author, assignee, milestones, dates, full-text).
  Use when the user asks to find, list, or filter GitHub issues/PRs across one or more repos, or to cross-check
  trackers (bugs, incidents, regressions) on github.com or GitHub Enterprise.
  Trigger phrases: "GitHub issue", "search issues", "repo bugs", "is:issue", "is:open", "label:", "gh issue".
---

# GitHub Issue Search

Query GitHub issues and pull requests with the **Search API**. Prefer machine-readable JSON (`curl` or `gh api`) so results are easy to summarize.

## Authentication

Use a **fine-grained or classic PAT** with at least `read-only` access to the relevant repositories (or `public_repo` for public repos only).

- Read token from `GITHUB_TOKEN` or `GH_TOKEN` (do not print or log the value).

### Investibook (server / workspace)

Same pattern as **`CLINIC_API_KEY`**: if the backend process has a token, it is written to `workspaces/<id>/.env` on `POST /api/workspace/init` (and example workspace setup), and session bootstrap applies the same “expected block not in file → write `.env`” check as Clinic. Resolve order:

1. **`SKILL_GITHUB_TOKEN`** (preferred, mirrors `SKILL_CLINIC_API_KEY`)
2. **`INVESTIBOOK_GITHUB_TOKEN`**
3. **`GITHUB_TOKEN`** or **`GH_TOKEN`**

The ACP agent subprocess also gets `GITHUB_TOKEN` and `GH_TOKEN` injected from those variables so `curl` / `gh api` work without `source .env`.

- Send header: `Authorization: Bearer <token>`
- Send header: `Accept: application/vnd.github+json`
- Optional: `X-GitHub-Api-Version: 2022-11-28`

**GitHub Enterprise Server:** set host to `https://<hostname>/api/v3` instead of `https://api.github.com`.

## Primary API

**GET** `https://api.github.com/search/issues`

| Parameter | Notes |
|-----------|--------|
| `q` | Search query (see below). **Required.** |
| `per_page` | 1–100, default 30 |
| `page` | Pagination |
| `sort` | Optional: `comments`, `reactions`, `reactions-+1`, `interactions`, `created`, `updated` (only when supported for the query) |
| `order` | `asc` or `desc` |

**Response:** JSON with `total_count`, `incomplete_results`, and `items[]`. Each item includes `html_url`, `title`, `state`, `labels`, `user`, `assignees`, `created_at`, `updated_at`, `repository_url` (for cross-repo search), etc.

**Rate limits:** Search is rate-limited separately from core REST. On `403` / `Retry-After`, back off and reduce concurrency. If unauthenticated, expect strict limits — always use a token for agent workflows.

## Query language (`q`)

Combine keywords and qualifiers (space = AND). Useful qualifiers:

| Qualifier | Example |
|-----------|---------|
| Scope to repo | `repo:pingcap/tidb` |
| Issue vs PR | `is:issue` / `is:pr` |
| State | `is:open` / `is:closed` |
| Label | `label:bug`, `label:"type/enhancement"` |
| Author | `author:octocat` |
| Assignee | `assignee:@me`, `no:assignee` |
| Mention | `mentions:username` |
| Milestone | `milestone:"v8.5"` |
| Created / updated | `created:>=2026-01-01`, `updated:>2026-03-01` |
| Full text | free words: `slow query oom` |
| Exclude | `-label:duplicate` |

**Examples**

- Open bugs in one repo: `repo:org/repo is:issue is:open label:bug`
- PRs by label: `repo:org/repo is:pr label:cherry-pick-request`
- Org-wide text search: `org:pingcap slow query` (respect visibility; token must have access)
- Linked to a user: `involves:username is:issue is:open`

Encode `q` for URLs (e.g. `+` or `%20` for spaces). In shell, pass `--data-urlencode` (see below).

## Implementation: `curl` (preferred)

```bash
TOKEN="${GITHUB_TOKEN:-$GH_TOKEN}"
Q='repo:org/repo is:issue is:open label:bug'

curl -sS -G "https://api.github.com/search/issues" \
  --data-urlencode "q=${Q}" \
  --data-urlencode "per_page=30" \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "X-GitHub-Api-Version: 2022-11-28"
```

Pipe through `jq` to list URLs and titles:

```bash
... | jq -r '.items[] | "\(.html_url)\t\(.title)"'
```

## Implementation: GitHub CLI

If `gh` is installed and authenticated (`gh auth login`), use JSON output:

```bash
gh api -X GET "/search/issues" -f q='repo:org/repo is:issue is:open' -F per_page=30
```

For Enterprise: `GH_HOST=hostname gh api ...`

## Workflow for agents

1. **Clarify scope** — org vs repo list, issue vs PR, open vs all, label keywords.
2. **Build `q`** — start narrow (`repo:` + `is:issue` + state); widen only if empty.
3. **Call API** — one page first; paginate with `page=` if `total_count` exceeds `per_page`.
4. **Summarize** — title, state, labels, URL, created/updated; quote sparingly.
5. **Errors** — `401` bad/missing token; `403` rate limit or missing repo scope; `422` invalid query syntax.

## Privacy and safety

- Do not paste tokens into chat, logs, or committed files.
- Do not exfiltrate private issue bodies unless the user explicitly needs them; listing metadata is usually enough.
- If results are empty, say so and suggest relaxing `q` (remove labels, broaden text, check repo name spelling).
