Skip to main content

heinzel-github

Read pull requests and issues from GitHub, the code-host and tracker capabilities (ADR 0028): a first-party Heinzelmännchen plugin.

Install it with:

hz system plugin add github --confirm
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.

Screenshots

The fictional weekly code review in the Core workflow graph and contracts list

The fictional weekly code review in the Core workflow graph and contracts list

Fictional weekly review declares merged-work and issue inputs; no report was generated

Fictional weekly review declares merged-work and issue inputs; no report was generated

Fictional merged pull requests in the app terminal, using a fixture-only requester and the real adapter

Fictional merged pull requests in the app terminal, using a fixture-only requester and the real adapter

Fictional issue changes, owners and states in the app terminal, using a fixture-only requester

Fictional issue changes, owners and states in the app terminal, using a fixture-only requester

Command line Read fictional merged work in the shell with a fixture-only requester and the real adapter

Read fictional merged work in the shell with a fixture-only requester and the real adapter

Fictional issue results as JSON for scripts and agents, using a fixture-only requester

Fictional issue results as JSON for scripts and agents, using a fixture-only requester

Open the screenshot gallery.

Release feed for draft workflows

With Heinzel 0.9.16 or newer, the GitHub plugin installed from a wheel can supply a release feed to a draft workflow. Give the workflow an exact HTTPS GitHub blob URL for the Markdown CHANGELOG. The feed reads the same repository's published release notes and the matching literal CHANGELOG section. It starts from the current release frontier and returns later releases in publication order.

An ambiguous tag, a lost frontier, or a full GitHub page of 100 entries including drafts stops the read without advancing the cursor. The feed uses gh and holds the selected credential privately for the read. It never stores or displays the token. Changing the selected account, configuration, or executable requires a new review.

Metadata

Release files for heinzel-github 0.9.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for heinzel-github 0.9.3
File Size Uploaded Provenance Actions
heinzel_github-0.9.3.tar.gz 687.8 kB Without provenance Details for heinzel_github-0.9.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for heinzel-github 0.9.3
File Interpreter ABI Platform Actions
heinzel_github-0.9.3-py3-none-any.whl Python 3 none any Details for heinzel_github-0.9.3-py3-none-any.whl

Total release size: 718.2 kB

Release files / heinzel_github-0.9.3.tar.gz

Download URL heinzel_github-0.9.3.tar.gz
Size 687.8 kB
Tags Source
SHA-256 checksum
How to use checksums
6c53a67f2630ecc7fd21a87c3813f691f29810adda3da47d0d399f8e1ef2ebbc
BLAKE2b-256 checksum
How to use checksums
1320717731c2eb8c1d5723e622130f619e33cee716c5ad404d4c1afdf5eafd97
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","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.3-py3-none-any.whl

Download URL heinzel_github-0.9.3-py3-none-any.whl
Size 30.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eb7f440310164090020fc2107664fad728b45955b4292648bf8f333a384d6ddd
BLAKE2b-256 checksum
How to use checksums
df201165e409860daf79f6b83df39b790898d528f9fbc07ebce42e1b7bc89912
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","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.3

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page