Read this first. On GitHub.com and GitHub Enterprise the Forge App is a GitHub App and everything works — see GitHub App setup. On GitLab, Gitea, and Forgejo it does not. The adapters exist in the source tree and are tested, but they are still not on a path a non-GitHub hive can reach. One caller now constructs an adapter from
project.forge— the governor's escalation writes (#5259) — and it is a genuine first step, but nothing feeds it on a GitLab or Gitea hive, because enumeration still requires a GitHub client. There is no non-GitHub setup path to follow yet, and this page exists so you can establish that in one read instead of discovering it after an install.
The dashboard and docs call the app Hive installs on your source control system the Forge App, and the docs call the system itself your forge. That naming is deliberately forge-neutral because the code abstraction underneath it is. The naming does not, on its own, imply the non-GitHub paths are finished — this page is the difference.
| Forge | Agents do work | Read API | Comment / label / hold | Open issues & PRs | Merge | Dashboard login |
|---|---|---|---|---|---|---|
| GitHub.com | Yes | Yes | Yes | Yes | Yes | Yes |
| GitHub Enterprise | Yes | Yes | Yes | Yes | Yes | Yes |
| GitLab (SaaS or self-managed) | No | Adapter only, unwired | Wired but unreachable | Not implemented | Not implemented | No |
| Gitea | No | Adapter only, unwired | Wired but unreachable | Not implemented | Not implemented | No |
| Forgejo | No | Adapter only, unwired | Wired but unreachable | Not implemented | Not implemented | No |
"Adapter only, unwired" means the Go code is written and covered by tests, but no
running code path calls it. "Wired but unreachable" is the narrower state the
comment/label column is now in: one production caller — the governor's
escalation sweep — selects its adapter from project.forge and would post the
evidence comment and needs-human label to your forge, but it is driven by the
GitHub-only enumeration the governor cycle starts from, which produces nothing
without a GitHub client.
The wiring is real; the input never arrives. hold is not in that caller and
stays unwired. Gitea and Forgejo share one adapter because they share one REST
API surface.
A hive cannot presently run against GitLab, Gitea, or Forgejo. If that is your forge, there is nothing to install and no configuration that will make agents work.
This is the state the roadmap records for the abstraction: the
adapters are built, the first production caller is behind the seam, and what
remains is the read path — neutralizing enumeration, which today owns hold-label
filtering, issue filters and SLA tracking inside pkg/github. The design
rationale is ADR-0005.
The forge abstraction and the thing agents actually run are two different mechanisms, and only the second one moves work.
Agents do not call the forge abstraction. They shell out to the gh CLI,
through the wrapper Hive installs ahead of it on PATH
(bin/gh-wrapper.sh), which injects a GitHub App installation token and
enforces the per-agent restriction rules. The higher-level helpers agents use to
file work — bin/hive-open-issue.sh, bin/hive-open-pr.sh, bin/hive-merge.sh
— are all built on that same gh path. There is no glab equivalent, no Gitea
CLI, and no forge-neutral shell entry point.
The wrapper does not even let an agent call GitHub directly for writes: it
intercepts gh pr create, gh issue create, and gh issue comment and redirects
them to those helpers, which write request files that the hive daemon consumes
and executes with an App installation token. The GitHub MCP server's write tools
are explicitly denied for the same reason, so that route is closed too.
So the write path that matters — open an issue, push a branch, open a PR, merge
it — is GitHub-shaped end to end, independently of anything project.forge says.
Three further consequences follow, and each is load-bearing:
- Authentication. Every credential path is a GitHub App: App ID, private key, installation ID, per-tier minted installation tokens. GitLab and Gitea have no GitHub App, so none of that machinery has an analogue. The adapters authenticate with a plain personal access token instead, which is why they could never simply inherit the existing credential plumbing.
- Dashboard login. Signing in uses GitHub OAuth or a configured OIDC provider.
There is no GitLab or Gitea login provider, including for a hive whose
project.forgenames one. - Webhooks. Both forge webhook receivers verify
X-Hub-Signature-256and readX-GitHub-Event. There is no GitLab (X-Gitlab-Token) or Gitea receiver.
src/pkg/forge is a genuine, tested abstraction, written so Hive is not
permanently welded to GitHub. It defines a forge-neutral Forge interface plus
neutral types — note ChangeRequest rather than "pull request", since that is a
GitHub term — and three adapters: GitHub (wrapping pkg/github), GitLab (REST
v4), and Gitea/Forgejo (REST v1).
All three implement the same operation set:
| Operation | Meaning |
|---|---|
GetRepo |
Fetch one repo/project by its slug |
ListOpenIssues |
Open issues (GitHub's adapter filters out PRs, which its REST API models as issues) |
ListOpenChangeRequests |
Open pull requests / merge requests |
CreateIssueComment |
Comment on an issue or change request |
AddLabels / RemoveLabel |
Label maintenance |
SetHold |
Apply or clear the hold merge gate, via the label |
What is deliberately absent matters as much as what is present:
- No merge primitive.
Mergeris declared as an optional extension interface that no adapter implements, and it carries aTODOin the source. Merge semantics diverge too sharply across forges — strategy names, gate checks, MR-versus-PR — to neutralize convincingly, so it was left explicit rather than half-built. - No issue or change-request creation. The interface has no
CreateIssueand noCreatePR. Even fully wired, the adapters could comment and label but could not file the work.
That second point is the ceiling on this path: the abstraction was scoped to the read path plus light write operations, not to the create-and-merge lifecycle an agent needs.
These keys parse and validate today. They are documented here because they are real and you will find them in the source — not because setting them makes a non-GitHub hive work. They have two consumers: the dashboard's Platform card, which reads them to display a forge name and instance URL, and the governor's escalation writes, which build an adapter from them (see the table above for why that caller is not reached on a non-GitHub hive today).
project:
forge: gitlab # "github" (default) | "gitlab" | "gitea"
gitlab:
gitlab_url: https://gitlab.example.com # default https://gitlab.com
token_env: GITLAB_TOKEN # env var NAME, never the token
gitea:
gitea_url: https://gitea.example.com # no default; required for Gitea
token_env: GITEA_TOKEN # env var NAME, never the tokenNotes that will save you a wrong guess:
gitlab:andgitea:are top-level blocks, siblings ofgithub:— not nested inside it.token_envnames the environment variable to read the token from. The token value is never written to config, matching Hive's no-secrets-in-config rule. UseGITLAB_TOKEN/GITEA_TOKENunless you have a reason not to.- Omitting
project.forgemeans GitHub, so every existing config is unaffected. - GitLab defaults to
https://gitlab.com. Gitea has no default — there is no single public Gitea host, so selecting the Gitea forge without a URL is a configuration error at client construction. - The instance URL is the bare instance root. The adapters append
/api/v4(GitLab) and/api/v1(Gitea) themselves; adding the suffix yourself produces a doubled path.
Two unrelated settings share the word "forge", and mixing them up is the most likely way to break a working hive:
| Key | Meaning | Values |
|---|---|---|
project.forge |
Which forge family a spoke executes against — selects the pkg/forge adapter (read by the dashboard and by the governor's escalation writes; see above) |
github, gitlab, gitea |
github.forge |
Which GitHub instance this hive's App and repos live on — drives App ID, app slug, and API URL | a GitHub host label |
github.forge is part of the GitHub App identity system and is fully live. Do
not set it to gitlab or gitea; those are not GitHub hosts and it is not that
kind of setting.
Should you exercise pkg/forge directly — from a test or your own program, which
is still the only way to reach most of it — the tokens it expects are ordinary
access tokens, not apps:
| Forge | Credential | Sent as |
|---|---|---|
| GitLab | Personal, project, or group access token | PRIVATE-TOKEN header |
| Gitea / Forgejo | Personal access token | Authorization: token <TOKEN> |
Scope them to the repositories the hive would work on, with read access to issues and merge/pull requests, plus write access to issue comments and labels if you intend to exercise the comment/label/hold operations. A token may be omitted entirely for unauthenticated reads of public projects; private projects and all writes require one. Use a throwaway token — this is an evaluation path, not a supported deployment.
One further caveat if you do: Hive's egress proxy enforces ACMM policy only on hosts registered for mode enforcement, which today are GitHub hosts and the Linear API. A GitLab or Gitea host is not among them, so its traffic is tunneled without request-level ACMM enforcement. An advisory-tier hive would not have its writes to such a host gated the way it would on GitHub — another reason this path is not deployment-ready.
Listed so the size of the gap is legible, not as a plan of record:
- A forge-neutral enumeration path. Today the governor cycle starts at
github.Client.EnumerateActionable, which also owns hold-label filtering, issue filters and SLA tracking, so neutralizing it means lifting that policy above the forge boundary — this is what makes the already-wired escalation writes unreachable on a non-GitHub hive. CreateIssueandCreateChangeRequeston theForgeinterface, plus a settledMerge— the create-and-merge lifecycle agents depend on.- A forge-neutral agent execution path, since agents reach their forge through
the
ghCLI wrapper rather than throughpkg/forge. - Credential plumbing for token-based forges alongside the GitHub App minting machinery, including per-tier scoping.
- A GitLab/Gitea dashboard login provider.
- Egress-proxy mode enforcement registration for the non-GitHub hosts.
- GitHub App setup — the supported path: app creation,
permissions, Setup URL, and
/gh-setup. - Getting started — first-session setup, including Step 0.
- Troubleshooting — Forge App and credential symptoms.
- Operator reference — the full configuration surface.