markdown · 3125 bytes Raw Blame History

Search

Per-type search over shithub's Postgres FTS corpus. Every result set is filtered by the caller's visibility — anonymous callers see only public rows.

Response shape

Every endpoint returns the canonical gh-compatible envelope:

{
  "total_count": 142,
  "incomplete_results": false,
  "items": [
    { /* type-dependent record */ }
  ]
}

incomplete_results is always false in v1 (the FTS pipeline runs to completion before responding). The field is preserved on the wire so future ranker timeouts can flip it.

total_count is the unbounded result count.

Query syntax

The q= parameter is parsed by internal/search/query_parse — free-text terms plus the following operators:

  • repo:owner/name — restrict to one repo
  • is:open / is:closed (or state:open / state:closed)
  • author:username
  • "quoted phrase" — phrase search (one phrase per query)

Unknown prefixes (e.g. language:Go) fall through as free text so future operator additions don't break older queries.

Search repositories

GET /api/v1/search/repositories?q=...&page=N&per_page=M

Scope: repo:read for authenticated callers; anonymous callers fall through to the public-only filter.

{
  "total_count": 1,
  "incomplete_results": false,
  "items": [
    {
      "id": 12,
      "name": "demo",
      "full_name": "alice/demo",
      "owner_login": "alice",
      "description": "demo repo",
      "visibility": "public",
      "private": false,
      "star_count": 0,
      "updated_at": "2026-05-12T05:00:00Z",
      "score": 0.42
    }
  ]
}

Search issues

GET /api/v1/search/issues?q=...&type=issue|pr

Scope: repo:read. type=issue or type=pr narrows to one kind; omit to return both (issues share their table with PRs).

{
  "id": 17,
  "number": 1,
  "repo_id": 12,
  "repo": "alice/demo",
  "title": "needle in haystack",
  "state": "open",
  "kind": "issue",
  "author_name": "alice",
  "updated_at": "2026-05-12T05:00:00Z",
  "score": 0.81
}

Search code

GET /api/v1/search/code?q=...

Scope: repo:read. Matches against the path-and-content index populated by the push pipeline. preview_line carries a single line of context for content hits; path-only hits omit it.

{
  "repo_id": 12,
  "repo": "alice/demo",
  "ref": "trunk",
  "path": "internal/foo/foo.go",
  "preview_line": "func Foo() error { return errors.New(\"foo\") }",
  "score": 0.55
}

Pagination

?per_page= (≤100, default 30) and ?page= are supported, with the standard Link: header (see overview). The total_count field is independent of the page slice — it counts all matching rows regardless of pagination.

Not yet shipped

  • GET /api/v1/search/commits — commit message search; requires a per-repo commit FTS index that doesn't exist yet.
  • GET /api/v1/search/users — backing query exists; REST surface pending; will land alongside §7 orgs/users follow-up.
  • sort= / order= — every endpoint currently sorts by FTS rank; exposing alternative sorts (created, updated, stars) is queued.
View source
1 # Search
2
3 Per-type search over shithub's Postgres FTS corpus. Every result
4 set is filtered by the caller's visibility — anonymous callers
5 see only public rows.
6
7 ## Response shape
8
9 Every endpoint returns the canonical gh-compatible envelope:
10
11 ```json
12 {
13 "total_count": 142,
14 "incomplete_results": false,
15 "items": [
16 { /* type-dependent record */ }
17 ]
18 }
19 ```
20
21 `incomplete_results` is always `false` in v1 (the FTS pipeline
22 runs to completion before responding). The field is preserved on
23 the wire so future ranker timeouts can flip it.
24
25 `total_count` is the unbounded result count.
26
27 ## Query syntax
28
29 The `q=` parameter is parsed by `internal/search/query_parse`
30 free-text terms plus the following operators:
31
32 - `repo:owner/name` — restrict to one repo
33 - `is:open` / `is:closed` (or `state:open` / `state:closed`)
34 - `author:username`
35 - `"quoted phrase"` — phrase search (one phrase per query)
36
37 Unknown prefixes (e.g. `language:Go`) fall through as free text
38 so future operator additions don't break older queries.
39
40 ## Search repositories
41
42 ```
43 GET /api/v1/search/repositories?q=...&page=N&per_page=M
44 ```
45
46 Scope: `repo:read` for authenticated callers; anonymous callers
47 fall through to the public-only filter.
48
49 ```json
50 {
51 "total_count": 1,
52 "incomplete_results": false,
53 "items": [
54 {
55 "id": 12,
56 "name": "demo",
57 "full_name": "alice/demo",
58 "owner_login": "alice",
59 "description": "demo repo",
60 "visibility": "public",
61 "private": false,
62 "star_count": 0,
63 "updated_at": "2026-05-12T05:00:00Z",
64 "score": 0.42
65 }
66 ]
67 }
68 ```
69
70 ## Search issues
71
72 ```
73 GET /api/v1/search/issues?q=...&type=issue|pr
74 ```
75
76 Scope: `repo:read`. `type=issue` or `type=pr` narrows to one
77 kind; omit to return both (issues share their table with PRs).
78
79 ```json
80 {
81 "id": 17,
82 "number": 1,
83 "repo_id": 12,
84 "repo": "alice/demo",
85 "title": "needle in haystack",
86 "state": "open",
87 "kind": "issue",
88 "author_name": "alice",
89 "updated_at": "2026-05-12T05:00:00Z",
90 "score": 0.81
91 }
92 ```
93
94 ## Search code
95
96 ```
97 GET /api/v1/search/code?q=...
98 ```
99
100 Scope: `repo:read`. Matches against the path-and-content index
101 populated by the push pipeline. `preview_line` carries a single
102 line of context for content hits; path-only hits omit it.
103
104 ```json
105 {
106 "repo_id": 12,
107 "repo": "alice/demo",
108 "ref": "trunk",
109 "path": "internal/foo/foo.go",
110 "preview_line": "func Foo() error { return errors.New(\"foo\") }",
111 "score": 0.55
112 }
113 ```
114
115 ## Pagination
116
117 `?per_page=` (≤100, default 30) and `?page=` are supported, with
118 the standard `Link:` header (see [overview](overview.md)). The
119 `total_count` field is independent of the page slice — it counts
120 all matching rows regardless of pagination.
121
122 ## Not yet shipped
123
124 - `GET /api/v1/search/commits` — commit message search; requires a
125 per-repo commit FTS index that doesn't exist yet.
126 - `GET /api/v1/search/users` — backing query exists; REST surface
127 pending; will land alongside §7 orgs/users follow-up.
128 - `sort=` / `order=` — every endpoint currently sorts by FTS rank;
129 exposing alternative sorts (created, updated, stars) is queued.