Skip to content

Decision 104: a ref minted from configuration carries the resolved GitHub host, and every outbound call reads the host off the ref

  • Status: proposed
  • Date: 2026-09-02
  • Work item: issue-311
  • Deciders: MadaraUchiha-314 (owner, via the ticket), the-loop (design)
  • Refines: decision-048 (a work item's host lives in its ref, unwritten for github.com), decision-042 (integrations: transport is a choice; gh inherits the operator's auth)

Context

Issue-130 put the host into the ref for work items that arrive through an event. Two families of code never learned about it: refs the graph mints from ticketing.github (no host, so github.com), which is where the Slack link for a pending decision comes from; and gh calls that pass owner/repo alone, which go wherever gh happens to point rather than where the work item is. The owner asked for an audit and for the host to come from the CLI config or from gh itself.

Decision

#What was chosenWhy
D1One resolver, five tiers: integrations.github.host → the host of api.baseUrl when it is not the public API → $GH_HOST → the origin remote of the repository at hand → github.com.The config file is the declaration the-loop documents and validates; GH_HOST and the remote are gh's own answers, in gh's own order; nothing a remote says outranks what the operator wrote down.
D2The host enters at minting, as a separate argument. derive_ref/ref_for take host; the owner/repo slug contract is unchanged.A ref's meaning must not depend on the machine reading it (the portable record travels); the explicit host in the ref is decision-048's answer and this keeps it. Smuggling a host into the slug would make one validation accept two shapes.
D3Every outbound call reads the host off the ref through one helper (--hostname for gh api, [host/]owner/repo for --repo), written only when the host is not the default.github.com deployments stay byte-identical; a call site cannot forget the host because it never spells it.
D4The API transport derives https://<host>/api/v3 only when baseUrl is the public default.An explicit baseUrl is the operator's and is honoured verbatim (decision-042); a hosted ref against the default base is the case nobody configured and the one worth deriving.
D5routing.workspace.defaultHost stays.It names a directory, has an explicit key, and the payload's html_url wins over it; folding it in would change a documented key for no behaviour.

Consequences

Good. The Slack link, the ask's link, the portable record's URL, the reviewer's pull-request list, every comment, reaction, poll read and integration call agree with the work item's host. A github.com deployment sees no change in any string. Enterprise poll sources can say ghe.corp/owner/repo.

Costs, accepted. One more optional key; one git config read per in-session graph command; the-loop's own homes (self-diagnosis, the marketplace, the dashboard origin) still live on github.com, which is a fact about the-loop and not the operator's GitHub.

Alternatives considered

AlternativeWhy not
A configurable DEFAULT_GITHUB_HOSTThe ref would mean different things on different machines
ticketing.github.host in the harness configThe daemon never reads the harness config (decision-032), and the issue names the CLI config
GH_HOST in every spawned gh's environmentPer process, not per call; two hosts would need two daemons

Released under the MIT License.