heinzel-github
Read pull requests and issues from GitHub, the code-host and tracker capabilities (ADR 0028): a first-party
Heinzelmännchen plugin. It is independently released and installed explicitly:
hz system plugin add github --confirm # a compatible plugin release; run it again to upgrade
hz system plugin remove heinzel-github
Set up
The adapter talks to GitHub only through the GitHub CLI gh (2.40.0 or later), which owns
authentication (ADR 0035). It reads what you can read, as you:
no app to register, no token to create or store. Install gh and log in once:
gh auth login # or: gh auth login --hostname ghe.example.com
The adapter acts with whatever that login may do, which is usually more than reading; it only ever sends GET
requests. As for any gh command, a GH_TOKEN or GITHUB_TOKEN (GH_ENTERPRISE_TOKEN for a GitHub Enterprise
Server) in your environment takes precedence over the stored login: it is gh's own variable, passed to gh and never
read by Heinzelmännchen. If you stored a token for an earlier version, remove it:
hz system credential remove github-token --service github (or unset HZ_CREDENTIAL_GITHUB_GITHUB_TOKEN).
Bind the adapter in your user configuration, never in a project hz.toml, which Heinzelmännchen ignores for bindings:
hz system config set capabilities.code_host github
hz system config set capabilities.tracker github
which writes
[capabilities]
code_host = "github"
tracker = "github"
Or per shell: HZ_CAPABILITIES__CODE_HOST=github, HZ_CAPABILITIES__TRACKER=github.
For GitHub Enterprise Server, name its host in your user configuration or HZ_GITHUB__HOST; the adapter passes it to
gh as --hostname and GH_HOST, so gh uses its login for that host:
hz system config set github.host ghe.example.com
or in the file (api_url from earlier versions is refused; host replaced it):
[github]
host = "ghe.example.com"
gh = "gh" # the GitHub CLI: a name on PATH (absolute entries only) or an absolute path
timeout = 60 # seconds per gh call
host, gh and timeout are ignored in a project hz.toml, so a repository can't send your login elsewhere or pick
the program that runs. The adapter's hosts come
from it: hz system capability list shows api.github.com, or your GitHub Enterprise Server's host.
Is it connected?
Bound automatically while it is the only installed adapter of a capability (usually code-host; tracker once another
tracker is installed needs a choice), ADR
0055. hz system connector list (or Settings → Connectors in hz ui) shows whether gh is logged in and as whom, read from gh's
hosts file without asking GitHub; hz system connector test github asks GitHub who gh is (gh api user, 15 s at most),
and only when you run it.
Use
Workflows ask for code-host and tracker, never for GitHub:
from datetime import datetime
from heinzel import CodeHost, Module, PullRequest, Window
module = Module("digest", "Weekly digest.", requires=["code-host:read", "tracker:read"])
@module.operation
def merged(code_host: CodeHost, since: datetime, until: datetime) -> list[PullRequest]:
"""Pull requests merged this week."""
return code_host.merged_pull_requests("acme/widgets", Window(since=since, until=until))
| Method | Capability | gh api call |
|---|---|---|
merged_pull_requests(repository, window) |
code-host:read |
repos/{owner}/{repo}/pulls?state=closed&sort=updated&direction=desc, kept when merged_at is in the window; paging stops before the window |
issues_updated(project, window) |
tracker:read |
repos/{owner}/{repo}/issues?state=all&since=...&sort=updated&direction=asc, without pull requests |
Repositories and projects are written owner/repo; windows are half-open [since, until) with timezone-aware times;
results are oldest first. The adapter pages with the API's page and per_page parameters rather than
gh api --paginate, so it can stop as soon as the window is covered. A call reads at most 100 pages of 100 (10,000
items), 50 MiB in all and ten times github.timeout, then fails and says what to ask for instead: merged pull requests page through every pull request updated since since, even after until, so they need
a window that starts more recently; issues stop at until, so they need a shorter window. Why the pulls list and not
the search API: ADR 0033; why gh:
ADR 0035.
hz github info # this plugin, its version and the GitHub host it reads
hz system capability list # who reads what, through which adapter and hosts
hz system doctor # gh on PATH, its version and login, the bindings; never contacts GitHub
Errors say what to do: no gh, or one too old, names where to get it; no login, or a login GitHub rejects, names
gh auth login --hostname <host>; a rate limit says to wait and how to see when it resets; a missing or forbidden
repository says to check the spelling and what your account can see; a slow call names the timeout setting.
How gh is run: with an argument list, never a shell, from your home directory, in its own process group, stopped
(SIGTERM, then SIGKILL) at the timeout, with its output capped, and with an allowlisted environment: never
Heinzelmännchen's HZ_CREDENTIAL_* variables or debug switches such as GH_DEBUG, which would print request
headers. Doctor runs only gh --version and looks for the host in gh's hosts file (or a token variable gh reads); it
never runs a command that prints a token. Everything GitHub or gh says is redacted of anything shaped like a GitHub
token, stripped of control and bidirectional characters, and only then cut to length; every string the adapter
returns is cleaned too.
Development and release commands: repository guide.
Migration provenance: heinzel, before the 0.9 plugin-boundary migration.
Metadata
Release files for heinzel-github 0.9.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| heinzel_github-0.9.1.tar.gz | 84.5 kB | Without provenance | Details for heinzel_github-0.9.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| heinzel_github-0.9.1-py3-none-any.whl | Python 3 | none | any | Details for heinzel_github-0.9.1-py3-none-any.whl |
Total release size: 109.2 kB
Release files / heinzel_github-0.9.1.tar.gz
| Download URL | heinzel_github-0.9.1.tar.gz |
|---|---|
| Size | 84.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e90639a4752313e198d3e7391ce91e9ca069e97057fc5a23a907e3279f8c346b
|
|
BLAKE2b-256 checksum How to use checksums |
e9c7e196089a40b1d50cc3eec6e9161035e4aa79d59f0751112ba1d87476c8de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / heinzel_github-0.9.1-py3-none-any.whl
| Download URL | heinzel_github-0.9.1-py3-none-any.whl |
|---|---|
| Size | 24.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
407fa942d8253f8e5ccb646f2f3ef3af2b79b9b0143ebcc3ef24e2d317056dfa
|
|
BLAKE2b-256 checksum How to use checksums |
b95f12997eb1d69b711da976b3b342cdea4e9c7c037f97b6a33577d1ad3eb9c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for heinzel-github 0.9.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.