Concepts

Capabilities

How a provider declares which operations it supports, and how CI checks those claims.

Forges don't offer the same features: Bitbucket has no releases, and Tangled has no checks. Every provider declares what it supports in provider.capabilities.

Support levels

Each entry has one of four values:

ValueMeaning
trueNative and verified. A test exercises the operation.
'experimental'Native, but not verified against a recording of the live forge, or built on an API that the forge marks unstable.
'emulated'Composed from other calls, so its behaviour can differ from a native operation.
falseNot available. Calling it rejects with UnsupportedOperationError.

For example, Forgejo has no done state for notifications. Its notifications.markDone is 'emulated': it marks the notification read and unsubscribes from the thread.

Per thread kind

Support can differ by thread kind. GitHub closes issues, pull requests and discussions, while Cursor Origin has pull requests only. Those entries are objects keyed by kind, and can() takes the kind as a second argument.

Experimental providers

capabilities.experimental is true when the provider as a whole is experimental: its tests use hand-written fixtures only, or the forge's API is unstable. Gitee, Azure DevOps, Cursor Origin and pushin.eu are experimental providers.

Version-dependent support

Some capabilities depend on the instance version. GitHub Enterprise Server supports marking notifications done from version 3.13. The provider computes capabilities without a network request, so pass instanceVersion if you know it, or call refreshCapabilities().

How CI enforces it

A provider can declare true only for an operation that a test calls. During vitest run, test/setup/verbs.ts records each verb a test calls. pnpm test:capabilities then runs scripts/check-capabilities.ts, which fails for any capability that a provider declares true and no test called.

Provider pages and the capability matrix are generated from the same declarations, and a unit test fails when they're out of date.

Using capabilities

  • Call provider.can() before an operation that a forge might lack.
  • Use the matrix to decide which forges to support.
  • Read the limits entry for the text limits of a forge, such as the maximum comment length.
Copyright © 2026