Linux
One static binary, CGO_ENABLED=0, so there is no C library to install and no
distribution to match. A release archive and a PATH entry is the whole
install; everything below that is about doing it deliberately.
Pick the archive
Section titled “Pick the archive”Release archives are named
ghchronicle_<version>_linux_<arch>.tar.gz, with <arch> either amd64 or
arm64. uname -m answers which.
uname -m reports | The archive to take |
|---|---|
x86_ | linux_amd64 |
aarch64 | linux_arm64 |
VERSION=1.0.0arch=$(uname -m); case "$arch" in x86_64) arch=amd64 ;; aarch64) arch=arm64 ;; esacbase=https://github.com/jmrplens/ghchronicle/releases/download/v$VERSIONcurl -fsSLO "$base/ghchronicle_${VERSION}_linux_${arch}.tar.gz"Check what you downloaded
Section titled “Check what you downloaded”Two files are published beside the archives: checksums.txt, which holds the
SHA-256 of every archive, and checksums.txt.sigstore.json, which is a
signature over that file. So the chain is one signature and a digest: verify
the file, then verify the archive against the file.
-
Take the checksum file and its signature.
Terminal window curl -fsSLO "$base/checksums.txt"curl -fsSLO "$base/checksums.txt.sigstore.json" -
Check the archive against it.
--ignore-missingis what lets one line of a twelve-line file be checked without the other eleven archives being present.Terminal window sha256sum --ignore-missing -c checksums.txtghchronicle_1.0.0_linux_amd64.tar.gz: OK -
Check the checksum file itself, if you have cosign.
Terminal window cosign verify-blob \--certificate-identity-regexp 'https://github.com/jmrplens/ghchronicle/.github/workflows/release.yml@refs/tags/.*' \--certificate-oidc-issuer https://token.actions.githubusercontent.com \--bundle checksums.txt.sigstore.json \checksums.txtVerified OK
The signing is keyless: there is no public key to fetch and no private key for
anyone to lose, because the identity being verified is the workflow that ran,
recorded in a public transparency log. That is what the two --certificate
flags say, and why they are not optional: without them cosign would confirm
that somebody signed the file, which is not the question.
Put it on the PATH
Section titled “Put it on the PATH”The archive holds three files and no directory, so extract it somewhere you meant to.
Directoryghchronicle_1.0.0_linux_amd64.tar.gz
- ghchronicle the binary
- LICENSE
- README.md
tar -xzf ghchronicle_1.0.0_linux_amd64.tar.gz ghchroniclesudo install -m 755 ghchronicle /usr/local/bin/ghchronicle -versionmkdir -p ~/.local/bintar -xzf ghchronicle_1.0.0_linux_amd64.tar.gz -C ~/.local/bin ghchroniclechmod 755 ~/.local/bin/ghchronicleghchronicle -version~/.local/bin is on the PATH of most distributions already. If
ghchronicle -version answers “command not found”, it is not on yours.
ghchronicle 1.0.0 (commit 4e5dfc2, built 2026-09-14T23:04:02Z)Run it once
Section titled “Run it once”The binary needs a configuration file and a token, and the quickstart writes both in six steps. With those in place:
ghchronicle -config config.yaml -list # what would be collectedghchronicle -config config.yaml -once # one sweep, then exitKeep it running
Section titled “Keep it running”systemd is the arrangement this documentation treats as the default on Linux, and the unit there is hardened rather than minimal, because this is very likely the only process on the host holding a GitHub token with read access to every repository of an account.
A scheduler works too:
cron with -once is
a single line, at the cost of giving every family the same cadence.
Build it from source
Section titled “Build it from source”Go 1.27.1 or newer is what the module declares. Nothing else is needed: the
build sets CGO_ENABLED=0, so there is no compiler and no header package to
find.
go install github.com/jmrplens/ghchronicle/cmd/ghchronicle@latestLands in $(go env GOPATH)/bin, which is ~/go/bin unless you moved it,
and that directory has to be on your PATH.
A binary built this way reports its version but not its commit or its build date:
ghchronicle 1.0.0 (commit unknown, built unknown)The version comes from the VERSION file the module embeds; the other two
are stamped by the release build and by nothing else, and a module
downloaded through the proxy carries no checkout to read them from.
git clone https://github.com/jmrplens/ghchroniclecd ghchroniclemake build # into bin/ghchroniclemake install # into GOBIN, stamped like a release buildmake build stamps the version, the short commit and the commit date, so
-version says exactly which tree it came from. make with no target
lists every target there is.
Where the files go
Section titled “Where the files go”The collector looks for a configuration file in no particular place: -config
defaults to config.yaml relative to the working directory, and there is
no search path behind it. So the path is a decision you make once and then pass
on every invocation. What the rest of this documentation assumes:
| File | Path | Mode |
|---|---|---|
| Configuration | /etc/ghchronicle/config.yaml | world readable, no secrets |
| Tokens | /etc/ghchronicle/ghchronicle.env | 600 |
| State and ledger | /var/lib/ghchronicle/ | written by the service user |
state_file has a default of its own, ghchronicle-state.json in the working
directory, with the write ledger beside it as
ghchronicle-state-written.bin. That default is fine for a first run in a
directory you made, and wrong for a service, whose working directory is not
something to rely on. Set it.