One contract, honest differences

Adapters normalize the portable work-item model while preserving provider-native state names, raw payloads, capabilities, and failure behavior. The goal is portability without pretending every tracker works the same way.

Provider entry points

providers.ts
import { github } from "work-sdk/github";
import { gitlab } from "work-sdk/gitlab";
import { linear } from "work-sdk/linear";
import { jira } from "work-sdk/jira";
import { azureDevOps } from "work-sdk/azure-devops";

Subpath exports keep provider implementations independently tree-shakeable. All adapters return the same WorkAdapter contract.

Capability matrix

CapabilityGitHubGitLabLinearJiraAzure DevOps
Create / updateYesYesYesYesYes
CommentsMarkdownMarkdownMarkdownADFMarkdown
Custom statesNoNoYesYesYes
PrioritiesNo universal fieldNo universal fieldNativeNative1–4 mapping
Multiple assigneesYesOpt-inNoNoNo
Parent linksNoNoYesYesYes
SearchNot in adapterREST searchGraphQL filtersJQLWIQL
ConcurrencyReadback revisionReadback revisionReadback revisionReadback revisionNative /rev test

GitHub Issues

github({
  owner: "acme",
  repo: "web",
  token: process.env.GITHUB_TOKEN,
})

The adapter excludes pull requests from issue results, maps open/closed reasons, verifies fields through readback, and supports multiple assignees. GitHub Projects fields are intentionally outside the portable issue contract.

NextGitHub guidePermissions, identifiers, mappings, safe writes, and limits.

GitLab

gitlab({
  project: "acme/platform",
  token: process.env.GITLAB_TOKEN!,
  // apiBaseUrl: "https://gitlab.example.com/api/v4",
})

The REST v4 adapter supports GitLab.com and Self-Managed. It validates labels before writes, requires explicit mappings for non-native issue kinds, and keeps tier-dependent multiple assignees opt-in.

NextGitLab guideAuth, Self-Managed, guarded labels, issue types, pagination, and concurrency limits.

Linear

linear({
  apiKey: process.env.LINEAR_API_KEY!,
  teamId: "team-id",
})

Linear uses cursor pagination, one assignee, native priorities, and team-specific workflow states. The adapter resolves state and label names against provider metadata before a mutation.

NextLinear guideTeams, identifiers, native priorities, workflows, and safe writes.

Jira Cloud

jira({
  baseUrl: "https://acme.atlassian.net",
  email: process.env.JIRA_EMAIL!,
  apiToken: process.env.JIRA_API_TOKEN!,
  projectKey: "ENG",
})

Jira status changes are transitions, not ordinary field updates. The adapter discovers available transitions and converts conservative text content to Atlassian Document Format.

NextJira guideAuthentication, workflow transitions, ADF content, fields, and limits.

Azure DevOps

azureDevOps({
  organization: "acme",
  project: "Platform",
  auth: { type: "entra", token: accessToken },
})

Azure DevOps uses WIQL for discovery and JSON Patch for mutation. Custom processes can redefine state and work-item type names, so the adapter exposes explicit normalization maps.

NextAzure DevOps guideAuthentication, custom process configuration, fields, pagination, and limitations.

Provider escape hatches

Every normalized item, user, project, and comment can retain raw. Use it for reads that are not portable. For provider-specific writes outside the adapter contract, build a narrow custom tool instead of mutating raw and pretending the operation is normalized.

Capability flags describe adapter-level support. Tenant workflow rules and user permissions can still reject an individual operation.