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
import { github } from "work-sdk/github";
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
| Capability | GitHub | Linear | Jira | Azure DevOps |
|---|---|---|---|---|
| Create / update | Yes | Yes | Yes | Yes |
| Comments | Markdown | Markdown | ADF | Markdown |
| Custom states | No | Yes | Yes | Yes |
| Priorities | No universal field | Native | Native | 1–4 mapping |
| Multiple assignees | Yes | No | No | No |
| Parent links | No | Yes | Yes | Yes |
| Search | Not in adapter | GraphQL filters | JQL | WIQL |
| Concurrency | Readback revision | Readback revision | Readback revision | Native /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.
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.
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.
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 guide →Authentication, 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.