Resource URIs
Use github as a database/sql-style driver so a host program can address GitHub as github:// URIs.
github is a command line, but the gh Go package is also a driver that makes github.com addressable as resource URIs.
A host program registers it the way a program registers a database driver with database/sql, then dereferences github:// URIs without knowing anything about how the site is read.
The host that does this today is ant, a single binary that puts one URI namespace over a family of site tools.
The examples below use ant; any program that links the package gets the same behaviour.
Mounting the driver
A host enables the driver with one blank import, exactly like import _ "github.com/lib/pq":
import _ "github.com/tamnd/github-cli/gh"
The package's init registers a domain with the scheme github, the alias gh, and every hostname that means GitHub: github.com, raw.githubusercontent.com, gist.github.com, gist.githubusercontent.com, and codeload.github.com.
A pasted raw or gist link resolves here rather than falling through as an unknown site.
The standalone github binary does not change.
The addressable types
A URI is scheme://authority/id, and the authority is the kind:
| URI | What it is |
|---|---|
github://repo/golang/go |
a repository |
github://user/torvalds |
a user |
github://org/golang |
an organization |
github://issue/golang/go#1 |
an issue |
github://pr/gohugoio/hugo#13000 |
a pull request |
github://discussion/gohugoio/hugo#13396 |
a discussion |
github://commit/golang/go@6db72bb |
a commit |
github://branch/golang/go@master |
a branch |
github://tag/golang/go@go1.24.0 |
a tag |
github://release/golang/go@go1.24.0 |
a release |
github://file/golang/go@master/src/net/http/server.go |
a file at a revision |
github://tree/golang/go@master/src |
a directory at a revision |
github://label/golang/go/NeedsFix |
a label |
github://milestone/golang/go/1 |
a milestone |
github://topic/go |
a topic |
github://gist/33cc3a9b0e37f5eb62dbd2a8e0f0eb8f |
a gist |
github://package/open-telemetry/opentelemetry-collector-contrib/opentelemetry-collector-contrib/telemetrygen |
a published package |
github://action/checkout |
a marketplace action |
github://wiki/golang/go/Home |
a wiki page |
github://advisory/GHSA-2xrv-8j4g-h47j |
a security advisory |
github://compare/golang/go@go1.23.0...go1.24.0 |
a range, which names no single thing |
github://contributor/golang/go@rsc |
one person's counts in one repository |
github://contribution/torvalds@2026-07-01 |
one day of a calendar |
github://event/... |
one entry in an activity feed |
The grammar has three separators and each one means exactly one thing.
/ separates a namespace from a name, and a repository from a path.
# introduces a thread number.
@ introduces a git revision.
A path may contain slashes but the revision always comes straight after the repository and the number is always last, so github://file/golang/go@master/src/net/http/server.go parses without ambiguity.
The last three kinds are records GitHub derives rather than serves.
No page's address is one contributor's statistics or one day of a calendar, so they get a URI and no canonical URL, and github url points at the page they were read from instead of inventing one.
An event has neither, and says so: its own url field is the only address it has.
ant get github://repo/gohugoio/hugo # the record
ant cat github://file/gohugoio/hugo@master/go.mod # the bytes
ant ls github://org/golang # the org's repos, each addressable
ant url github://pr/golang/go#1 # the live https URL
The same resolution works in the binary without a host:
github url https://github.com/golang/go/blob/master/go.mod
github url golang/go#1
github url github://release/golang/go@go1.24.0
Parsing does no I/O and never fails on a well-formed github.com URL.
Two of its answers are guesses and both are documented as such: a bare word is a user, because a pure function cannot tell a user from an organization without asking, and a bare owner/name is a repository.
github get reads the page and returns a record whose kind is the truth.
Classification is a routing hint, not an answer.
Walking the graph
Every record carries typed edges to the other things it names, so a host can follow them and write the result to disk:
ant export github://org/golang --follow 1 --to ./data
Because the edges are typed and the vocabulary is fixed, ant graph walks them the same way github crawl does, and across tools when an edge points at another site's scheme.
See walk the graph for the predicate list.
Why this is the same code
The driver and the binary share one definition per operation.
A resolver op answers both github repo on the command line and ant get github://repo/... through a host, from the same handler and the same client, with the same pacing and the same response cache.
There is no second implementation to keep in step.
Next: add a command.