Restoring forge operations beyond releases, in lockstep across providers¶
- Authors
- Matt Cockayne, Claude Opus 4.8 (AI drafting assistant)
- Date
- 2026-07-19
- Status
- DRAFT — records a deferred capability set and the constraint on reintroducing it. Not scheduled; no implementation should begin against it as written.
Why this exists¶
forge and its provider modules currently cover releases only. That is not
the whole story of what the code could do.
The GitHub provider was originally written for — and lifted from — a much older variant of go-tool-base, when GitHub was the default forge. It carried a substantially wider API. When the framework was opensourced, most of that functionality stopped being used by the framework itself, but the code was retained deliberately, because it still has value.
At the point of extracting forge-github, only the release surface came across.
This spec records what was left behind, why, and the condition on bringing it
back.
What was deferred¶
All of the following remain in go-tool-base/pkg/vcs/github and are not
deleted:
| Capability | Methods |
|---|---|
| Pull requests | CreatePullRequest, GetPullRequestByBranch, UpdatePullRequest, AddLabelsToPullRequest |
| Repositories | CreateRepo |
| SSH keys | UploadKey |
| File contents | GetFileContents |
| Interactive auth | GHLogin — OAuth device flow, via cli/oauth |
Only UploadKey has a caller inside go-tool-base today (pkg/setup/github).
The rest have none — which measures current framework usage, not value: this
is a framework, its packages are exported, and a downstream tool may well be
calling them.
The constraint¶
No capability ships for one provider alone.
This is the whole point. forge's design goal is that consuming code depends on
forge.Provider, not on *github.Client — so switching forges is a constructor
change, not a rewrite. A method that exists only on GitHub breaks that in the
worst way: the code compiles, the tests pass, and the portability claim silently
becomes false. A caller who reaches for it has left the contract without being
told.
The disparity that produced this spec is exactly that failure, caught before it was published. Reintroducing the capabilities one forge at a time would recreate it.
Shape of the eventual work¶
Not a design, but the constraints any design must satisfy:
Capability interfaces, not Provider methods. Adding methods to Provider
breaks every implementation, including out-of-tree ones nobody can see. The
existing precedent is ChecksumProvider and SignatureProvider: optional
interfaces discovered by runtime type assertion, with ErrNotSupported as the
opt-out. Something like PullRequestProvider, RepositoryProvider,
FileProvider follows that grain.
Lockstep means all four, or none. A capability lands when GitHub, GitLab,
Gitea and Bitbucket can all satisfy it — or when a platform genuinely cannot,
and returns ErrNotSupported by design rather than by omission. The
distinction matters: Bitbucket Downloads has no tagged releases, which is a
platform fact and documented as such. "Nobody has written it yet" is not.
The conformance harness must enforce it. forgetest.RunProviderConformance
already checks capability declarations in both directions. Whatever shape these
take, the harness has to be able to tell a deliberate opt-out from an
unimplemented one, otherwise lockstep is a convention rather than a guarantee —
and conventions erode.
Auth is not a capability. GHLogin is an interactive OAuth device flow.
That belongs to whatever is setting up a tool rather than to the release
contract, and it should not be smuggled in under this heading.
Open questions¶
Q1 — Is this forge's remit at all? forge was named over releases
precisely to leave room for this (see the VCS stack extraction plan, R6). But
pull requests and repository administration are a different problem from
publishing and consuming releases, and a separate module family may serve both
better than one widening interface.
Q2 — What is the actual demand? Only UploadKey has an in-tree caller. The
rest is retained on the judgement that it has value, which is worth confirming
against real downstream usage before four implementations are written.
Q3 — What do the non-GitHub platforms actually support? GitLab and Gitea have comparable pull/merge request APIs; Bitbucket Cloud differs more. Some capabilities may be genuinely impossible on one platform, which is fine — but it needs establishing per capability, not assumed.
Q4 — Does the existing code survive the move? It was written against go-github directly, for a single forge, before this contract existed. It is a starting point and a record of intent; it should not be assumed portable.
Status¶
DRAFT (2026-07-19) — captured at the point of the forge-github extraction so
the deferral is deliberate and recorded rather than an omission nobody notices.
Requires Q1–Q4 before any implementation.