<!-- generated by build_articles.py — edit content/answers/search-github-issues-and-prs-locally.md instead -->
---
title: "Search GitHub issues and PRs locally"
canonical: "https://xerj.org/answers/search-github-issues-and-prs-locally"
updated: "2026-10-20"
source: "content/answers/search-github-issues-and-prs-locally.md"
---

# Search a repo's issues and pull requests on your machine

**Short answer** (updated 2026-10-20): Search a repo's issues and pull requests locally. Export them to JSONL, index the folder, and query that index instead of reading `gh` JSON. On 2026-10-20 the `gh` capture file was 36,550 bytes and the `xerj search` capture file was 1,865 bytes. Two of the three passages were cited as line 1.

**Key number:** The captured gh search file was 36,550 bytes and the xerj search file was 1,865 bytes. (as of 2026-10-20; source: [benchmarks/agent-queries-2026-10-20/01-byte-compare.txt](https://github.com/xerj-org/xerj/blob/main/benchmarks/agent-queries-2026-10-20/01-byte-compare.txt))

**TL;DR** — Search a repo's issues and pull requests locally. Export them to JSONL, index the folder, and query that index instead of reading `gh` JSON. On 2026-10-20 the `gh` capture file was 36,550 bytes and the `xerj search` capture file was 1,865 bytes. Two of the three passages were cited as line 1.

## Agent prompt

```text
Read https://xerj.org/llms.txt. Start one local node. Export issues and pull requests to JSONL, run xerj autoindex, then search with a _search body that lists _source fields. Report number, title and state. If a passage is cited as line 1 for two different issues, trust number and title, not the line.
```

## Commands

### Command 1

Note: Index the export. 1,532 records, wall 7.2 s.

```sh
xerj autoindex --url http://127.0.0.1:9217 --yes --no-graph --progress plain --disable-feedback /tmp/xerj-aq-2026-10-20/issues --prefix gh --state-dir /tmp/xerj-aq-2026-10-20/state-gh
```

### Command 2

Note: Three passages. Two were labeled issues.jsonl:1.

```sh
xerj search --url http://127.0.0.1:9217 --prefix gh -k 3 xerj feedback --open-pr commits and pushes
```

### Command 3

Note: The field list is what an agent should read. Issue 960 ranked first.

```sh
curl -s -XPOST http://127.0.0.1:9217/gh-*/_search -H 'content-type: application/json' -d '{"size":5,"_source":["number","title","state","url"],"query":{"multi_match":{"query":"xerj feedback --open-pr commits and pushes","fields":["title","body"]}}}'
```

XERJ is a new way for AI to search for data.

## Export, then index

The capture saved 532 issues and 1,000 pull requests from `xerj-org/xerj` (`gh pr list --limit 1000` returned 1,000). One JSON object per line. `xerj autoindex` committed 1,532 records in 7.2 s, exit 0. The datasets were `gh-jsonl` and `gh-json`, not a name you guess.

```text
xerj-done ok=true exit=0 reason=completed wall=7.2s files=2 records=1532 generation=1
```

## What the agent should call

```sh
xerj search --url http://127.0.0.1:9217 --prefix gh -k 3 "xerj feedback --open-pr commits and pushes"
```

Three passages came back. The command said they are lexical and that it does not consult the embedding. The default embedder is lexical feature hashing. `--embed-mode neural` was not on. Two passages were labeled `issues.jsonl:1`. The third had no line. The scores printed were 42.22, then 35.68, then 44.36, so the print order was not score order.

The lines from `feedback.rs` were inside the issue text. That is a quote of the issue, not a link from the issue to the code.

## Return the fields, not the body

```sh
curl -s -XPOST http://127.0.0.1:9217/gh-*/_search -H 'content-type: application/json' -d '{"size":5,"_source":["number","title","state","url"],"query":{"multi_match":{"query":"xerj feedback --open-pr commits and pushes","fields":["title","body"]}}}'
```

`took` was 7. Issue 960 was first. `_savings.bytes` was 19,444, `measured` `sampled`. The same question through `gh issue list --json number,title,body,state,url` produced a capture file of 36,550 bytes, because each hit included `body`.

`xerj mcp` against this node returned 17 tools, including `xerj_search`. The server does not start a node.

## Measured on 2026-10-20

| Check | Result |
|---|---|
| Index | 1,532 records, wall 7.2 s, exit 0 |
| `xerj search` capture file | 1,865 bytes, 3 passages, two labeled line 1 |
| `gh issue list --json` capture file | 36,550 bytes, bodies included |
| `_source` narrowed to 4 fields | `_savings` 19,444 bytes, sampled. `took` 7 |

The byte win sits next to the line-label loss. Use `number` and `title` when the line is 1.

## When not to use XERJ

If you need live issue state for one number, `gh issue view` is the current source. The index is the export you last wrote. Re-index when you refresh the file.

## FAQ

### Search repo issues and PRs locally?

Export both to JSONL and index the folder. Search `gh-*`. The capture held 532 issues and 1,000 pull requests.

### gh issue search returns too much JSON?

The captured `gh` file, with issue bodies, was 36,550 bytes. The captured `xerj search` file was 1,865 bytes. Narrow `_source` when you need fields, not a passage.

### Search GitHub issues without cloning the repo?

You do not clone. `gh` writes the export, and the index stays on the machine. The agent then calls search or `xerj mcp`.

### Does this link an issue to the code?

No. A passage quoted `feedback.rs` because the issue body contained those lines. There is no call graph.

### Why do two hits say line 1?

In this capture `xerj search` labeled two different passages `issues.jsonl:1`. Read `number` and `title` from `_source`.

## Evidence

- The issue export indexed in 7.2 s, 1,532 records, exit 0. — `benchmarks/agent-queries-2026-10-20/01-autoindex-issues.txt`
- xerj search's capture file was 1,865 bytes and the gh capture file was 36,550 bytes. — `benchmarks/agent-queries-2026-10-20/01-byte-compare.txt`
- The narrowed _search response reported _savings of 19,444 bytes, sampled. — `benchmarks/agent-queries-2026-10-20/01-duplicate-search.json`
- tools/list returned 17 tools. — `benchmarks/agent-queries-2026-10-20/05-tool-names.txt`

## Related

- [What's the easiest way to search JSON logs plus some old gzip text logs in the same folder?](/answers/search-json-and-jsonl-logs)
- [I need my agent to find a passage and cite the file, not dump the whole tree. How?](/answers/code-search-mcp-for-claude-code)
- [How do I keep a search index up to date as files change, without re-indexing everything?](/answers/keep-index-current-as-files-change)
- [Find duplicate GitHub issues before you file](/answers/find-duplicate-github-issues-before-filing)
