---
title: "Capabilities"
description: "How a provider declares which operations it supports, and what each level of support means."
canonical_url: "https://forges.link/concepts/capabilities"
---
# Capabilities

> How a provider declares which operations it supports, and what each level of support means.

Forges don't offer the same features. Bitbucket has no releases, for example, and Tangled has no checks. Rather than letting you find out by trial and error, every provider declares what its forge supports in `provider.capabilities`. This page explains what the declarations mean, so you know what to expect when you check one.

## Support levels

Each entry has one of five values, which tell you how much you can rely on the operation:

<table>
<thead>
  <tr>
    <th>
      Value
    </th>
    
    <th>
      Meaning
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <capability-level level="native">
        <code>
          true
        </code>
      </capability-level>
    </td>
    
    <td>
      The forge supports it natively, and a test verifies it against the forge's own responses.
    </td>
  </tr>
  
  <tr>
    <td>
      <capability-level level="experimental">
        <code>
          'experimental'
        </code>
      </capability-level>
    </td>
    
    <td>
      Verified like <code>
        true
      </code>
      
      , but built on an API that the forge marks as unstable or in preview, so it can change.
    </td>
  </tr>
  
  <tr>
    <td>
      <capability-level level="emulated">
        <code>
          'emulated'
        </code>
      </capability-level>
    </td>
    
    <td>
      The forge has no such operation, so the provider composes it from other calls. Its behaviour can differ from a native operation.
    </td>
  </tr>
  
  <tr>
    <td>
      <capability-level level="unverified">
        <code>
          'unverified'
        </code>
      </capability-level>
    </td>
    
    <td>
      The provider implements it, but no test has verified it against the forge's responses yet, so it may not work.
    </td>
  </tr>
  
  <tr>
    <td>
      <capability-level level="none">
        <code>
          false
        </code>
      </capability-level>
    </td>
    
    <td>
      Not available. Calling it rejects with <code>
        UnsupportedOperationError
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

The forge's own responses are either a [recording of the live forge](https://forges.link/contributing/record-fixtures) or a fixture written from the forge's documentation. We check on every commit to `forges` that each level above `'unverified'` has such a test, and that nothing such a test verifies stays `'unverified'`.

Forgejo has no done state for notifications, for example, so its `notifications.markDone` is `'emulated'`. To get as close as possible, the provider marks the notification as read and unsubscribes you from the thread.

<capability-example capabilities="notifications.markDone,notifications.markAllDone" providers="github,gitlab,forgejo,bitbucket">



</capability-example>

## Per thread kind

Support can also differ between kinds of threads. GitHub can close issues, pull requests and discussions, whereas Cursor Origin only has pull requests. For operations like these, the entry is an object with a value for each kind, and `can()` takes the kind as a second argument.

<capability-example capabilities="writes.close,writes.reopen" providers="github,gitlab,cursor-origin">



</capability-example>

## Experimental providers

Sometimes it isn't a single operation that can change, but the forge's API as a whole. Then `capabilities.experimental` is `true`. Cursor Origin, Pushin.eu, Tangled and Cloudflare Artifacts are experimental providers at the moment: Cursor Origin uses an alpha API, the APIs of Pushin.eu and Tangled are still young, and Cloudflare Artifacts is in open beta.

## Version-dependent support

Some capabilities depend on the version of the instance. GitHub Enterprise Server, for instance, supports marking notifications as done from version 3.13. Because the provider works out its capabilities without sending a request, it can't read the version by itself. Pass `instanceVersion` if you know it, or call `refreshCapabilities()` to let the provider find out.

## Anonymous providers

Capabilities also depend on credentials. An anonymous provider reports `false` for writes, notifications and subscriptions, and also for any read that the forge only serves to signed-in users. For example, GitLab only shows labels and milestones to signed-in users, so `can('repos.labels')` is `true` with a token and `false` without one. To see what each forge supports without credentials, turn on **Without credentials** in the [capability matrix](https://forges.link/reference/capability-matrix) or on a provider page.

## Kinds of credential

On some forges, what a provider can do also depends on the kind of credential. GitHub serves notifications only to classic tokens, for example, and an app without an installation can only list its installations. The provider reads the kind from its `auth` options, so `can('notifications.list')` is `false` for a GitHub provider with a fine-grained token. The capability matrix shows the best support of any credential and marks the cells where only some kinds have it, and the provider pages of these forges show the support of each kind.

## Using capabilities

Capabilities are useful in a few ways:

- Call [`provider.can()`](https://forges.link/guides/capabilities) before an operation that a forge might lack.
- Use the [capability matrix](https://forges.link/reference/capability-matrix) to decide which forges your tool can support.
- Read the `limits` entry for the text limits of a forge, such as the maximum length of a comment.


## Sitemap

See the full [sitemap](https://forges.link/sitemap.md) for all pages.
