Docs / {breadcrumb}
-{title}
-{description}
- {children} -A direct API call combines intent, provider translation, authorization, and an irreversible effect. Agents are especially vulnerable to retry ambiguity and stale context. Work SDK separates decision time from mutation time.
Plans are serializable and contain no credentials. The current snapshot explains the diff; expectedRevision makes the later commit conditional.
The fingerprint covers every signed plan field. If application code or an agent mutates the reviewed input, changes, warnings, target, or revision, commit rejects the plan before any provider request.
The fingerprint detects accidental mutation. It is not a user-authentication signature and should not be treated as one across untrusted boundaries.
Update and comment plans capture the item's opaque revision. Commit re-reads the item and fails closed if it changed. capabilities.concurrency reports whether the final provider mutation is atomic, uses a best-effort preflight, or has no protection. Azure DevOps updates use an atomic JSON Patch test /rev; GitHub, GitLab, Linear, and Jira retain a small read-to-write race window.
The default memory store atomically coordinates retries inside one process. Serverless, clustered, and job systems must supply a durable store with an atomic claim. Keys should identify the business event, for example github:webhook:delivery-123:comment, not the attempt. Work SDK binds each key to the normalized provider, action, target, and input.
replayed: true.WorkInFlightError; do not start a second write.WorkAmbiguousCommitError and require reconciliation.WorkConflictError before a provider mutation.Durability alone is insufficient. A store implemented as separate get and set operations can still duplicate writes across workers.
Warnings describe lossy mappings, ambiguous values, unsupported fields, or provider limitations. Commit requires acceptWarnings: true when warnings exist, forcing the caller to acknowledge them explicitly.
Acceptance means “the caller reviewed this risk.” It does not make an impossible provider operation possible; an adapter can still reject invalid or unsupported input.
Every committed token, account, domain, project, and webhook secret in these examples is intentionally fake. Both apps default to WORK_PROVIDER=memory and make no external network request.
Each app includes a tracked .env.example. Copy it to the ignored .env file, select one provider, and replace only that provider's values. Fake values consistently contain example or use reserved example domains.
Example 01
-A terminal application that prepares an update, prints the exact diff and warnings, asks for explicit approval, and commits the reviewed plan with a stable idempotency key. Typing anything except yes exits without a provider mutation.
Example 02
-A small HTTP service built with Node core APIs. It verifies an HMAC-SHA256 signature, validates a deployment event, prepares a Markdown comment, and uses the event ID as a business-stable idempotency key. Repeated deliveries return replayed: true.
The app also exposes GET /health, rejects invalid signatures before a provider call, limits request bodies to 64 KiB, and returns small JSON receipts.
| Demo default | Production replacement |
|---|---|
| Memory adapter | Authenticated GitHub, GitLab, Linear, Jira, or Azure DevOps adapter |
| Memory idempotency store | Transactional database or conditional durable store with atomic claims |
| Local fake webhook secret | Secret-manager value with rotation |
| Direct HTTP processing | Queue, retry policy, reconciliation, and dead-letter handling |
| Console output | Structured redacted logs and audit receipts |
Do not instantiate authenticated adapters in browser bundles. Provider tokens must never enter client-side code, model prompts, prepared plans, or logs.
The package has zero runtime dependencies and publishes ESM, CommonJS, and declarations for every subpath.
Create one client per provider configuration. The adapter owns credentials and provider-specific routing; the client owns safe-write semantics.
Use normalized fields for portable behavior and stateName or raw when a provider-native detail matters.
A repeated successful idempotency key returns the stored receipt with replayed: true instead of performing the mutation again.
IdempotencyStore with an atomic claim across processes.acceptWarnings: true.WorkConflictError, discard the plan and prepare again.WorkAmbiguousCommitError, reconcile provider state before another write.AbortSignal from request or job cancellation.work.capabilities before exposing optional actions.A single “update ticket” tool hides the most important boundary. Prefer a proposal tool that returns a plan and a commit tool that accepts only a trusted approval reference.
Do not let the model manufacture acceptWarnings, approval IDs, stored plans, or idempotency keys. Resolve those values inside trusted code.
Remove unsupported fields at tool-construction time. Limit single-assignee providers to one entry and hide comments, parents, priorities, or states when the configured adapter cannot represent them.
Store the entire prepared change, the displayed summary/diff, actor, policy result, timestamp, and approval scope. Commit the exact stored plan; never rebuild it from a model-produced summary.
Use stable trigger identity. Random attempt IDs defeat replay protection; vague keys can incorrectly deduplicate distinct effects.
When another actor changes the item after inspection, surface the conflict to the agent or user, prepare again from current state, show the new diff, and obtain new approval. Never mutate expectedRevision or force the stale write.
The memory adapter implements the full contract, clones returned values, advances revisions, supports capability overrides, and honors abort signals.
replayed: true.WorkAmbiguousCommitError and blocks retry.WorkConflictError.Every first-party adapter accepts an injected WHATWG-compatible fetch. Assert URLs, authentication, escaped queries, request bodies, pagination, readback, and error normalization without network traffic.
Prefer real Request, Response, and Headers objects in mocks. They catch casing, status, body-consumption, and header behavior that plain objects hide.
The repository exports a reusable internal conformance suite for first-party development. External adapters should verify the same invariants: stable identity, cloned reads, pagination, revision advancement, conflicts, comments, and cancellation.
| Layer | Purpose | Network |
|---|---|---|
| Core unit tests | Plans, integrity, warnings, idempotency, conflicts | None |
| Adapter protocol tests | Exact provider requests and responses | Injected fetch |
| Package smoke | ESM/CJS/types/subpath exports after packing | Local install |
| Sandbox integration | Tenant permissions and workflow metadata | Provider test tenant |
| Production canary | Credential and API drift detection | Read-only or isolated target |
Work SDK is a local TypeScript library. Credentials stay in your process and requests go directly to the configured tracker.
Install the package, configure a provider, read an item, and commit a safe update.
- 02Configure Entra or PAT auth, custom processes, WIQL search, priorities, and parent links.
- 03Design narrow tools, approval gates, stable idempotency keys, and conflict recovery.
- 04Review every client method, normalized type, capability, and commit receipt.
- 05Try an approval CLI or signed webhook bot locally with safe fake credentials.
-Provider adapters are separate subpath exports. Your application gets one normalized client without pulling unused provider code into the bundle.
-prepareUpdate reads the current item and creates an integrity-protected plan. No provider mutation occurs until commit.
| Provider | Import | Protocol | Distinctive behavior |
|---|---|---|---|
| GitHub Issues | work-sdk/github | REST | Open/closed state reasons, multiple assignees |
| GitLab | work-sdk/gitlab | REST v4 | Self-Managed, guarded labels, explicit type maps |
| Linear | work-sdk/linear | GraphQL | Cursor pagination, team workflow resolution |
| Jira Cloud | work-sdk/jira | REST v3 | ADF rich text, workflow transitions |
| Azure DevOps | work-sdk/azure-devops | REST + WIQL | JSON Patch revisions, custom processes, parent relations |
The adapter targets Azure DevOps REST API 7.1. The organization and project are path-scoped, so an accidentally supplied foreign project is rejected rather than silently redirected.
Use Entra access tokens for production applications, service principals, or managed identities.
PATs are convenient for local scripts and prototypes. They are sent as Basic credentials with an empty username.
PATs are long-lived credentials. Prefer Entra tokens in production, scope credentials to work-item access, rotate them, and keep them out of browser code and agent context.
Azure organizations can rename states and introduce custom work-item types. Reads must map provider names to the portable model; creates need the reverse mapping. Work SDK keeps both directions explicit.
Built-in defaults cover common Agile, Scrum, and Basic process names. Custom entries extend or override those case-insensitive defaults.
Provider-native state values remain accepted. Canonical writes such as completed use stateNameByCanonical; if several tenant names map to the same canonical state and no inverse is configured, the adapter fails as ambiguous instead of guessing.
| Work SDK | Azure DevOps | Notes |
|---|---|---|
title | System.Title | Required on create |
description | System.Description | Returned as provider HTML |
stateName | System.State | Exact provider state |
priority | Microsoft.VSTS.Common.Priority | urgent/high/medium/low → 1/2/3/4 |
assigneeIds[0] | System.AssignedTo | Identity ID, email, or resolvable name |
labels | System.Tags | Semicolon-separated provider field |
parentId | Hierarchy-Reverse relation | Existing parent replaced atomically |
revision | rev | Opaque string to consumers |
list builds an escaped WIQL query, fetches ordered IDs, and hydrates pages through the batch work-item endpoint. Cursors are opaque and scoped to this adapter.
WIQL offset pagination is not a snapshot. For long-running crawls, items changing between pages can move in the order. Use targeted filters and restart a crawl when strict snapshot semantics matter.
Prepared updates capture Azure's numeric rev. Commit first rechecks the normalized revision, then sends a JSON Patch test operation against /rev in the same mutation request. A stale write fails as WorkConflictError.
apiBaseUrl replaces https://dev.azure.com/{organization}. Point it at the collection root; the adapter appends the encoded project and API paths.
The token stays in your process and requests go directly to api.github.com. Inject fetch in tests or when your runtime requires a custom transport.
Fine-grained personal access tokens need repository access plus read and write permission for Issues. GitHub App installation tokens are preferable for multi-tenant applications because each installation has an explicit repository boundary.
Never expose a GitHub token to a browser or to an untrusted model prompt. Keep the Work SDK client in a server process or isolated tool runtime.
idThe decimal issue number as a string, for example "481".identifierA readable repository-qualified value such as octo-org/product#481.revisionA deterministic readback fingerprint used for preflight conflict detection.| Work SDK | GitHub | Notes |
|---|---|---|
| state | open / closed | Completed maps to closed; custom workflow states are not available. |
| assigneeIds | logins | Multiple assignees are supported when the repository allows them. |
| labels | label names | Unknown labels are rejected instead of silently created. |
| kind | issue | Pull requests are excluded from list results. |
The returned receipt is narrowed to UpdateCommitResult. GitHub cannot atomically test an issue revision during the write, so update concurrency is reported as preflight, not atomic.
raw for reads.project accepts a numeric GitLab project ID or a full path such as group/subgroup/project. Work SDK URL-encodes the path exactly once and keeps issue IDs project-scoped.
The token shorthand sends a GitLab private-token header and works with personal, project, or group access tokens where the GitLab tier permits them. Use explicit OAuth auth when the credential is an OAuth access token.
token and auth are mutually exclusive. Credentials belong in server-side environment variables and never in browser code, prompts, prepared plans, or logs.
Point apiBaseUrl at the instance REST v4 root. Rate limits, enabled issue types, tiers, and access-token rules can differ from GitLab.com, so treat instance policy as runtime configuration rather than SDK defaults.
GitLab creates missing labels when an issue write includes them. That is a second side effect hidden inside a normal issue mutation, so Work SDK resolves project labels first and rejects unknown values by default.
-Set allowCreateLabels: true only when the application policy explicitly allows label creation. The option changes a safety boundary and should not be enabled merely to suppress validation errors.
GitLab REST exposes issue, task, incident, and test_case. Work SDK maps issue and task directly. Bug, story, epic, and subtask have no universal GitLab equivalent and fail unless you configure an explicit map.
Use numeric GitLab user IDs in assigneeIds. Multiple assignees are tier-dependent and remain disabled by default. Set multipleAssignees: true only after confirming the target instance supports the behavior.
list forwards text search, assignee username, labels, and opened/closed state filters. The adapter uses opaque gitlab:page:… cursors and reads X-Next-Page or the standard Link header without depending on total-count headers.
The adapter fingerprints the issue fields that affect normalized behavior, then re-reads immediately before an update. GitLab REST does not expose an atomic issue revision precondition, so a small race window remains between that read and the PUT request.
-On WorkConflictError, discard the plan and prepare again. Always use a durable idempotency store for distributed workers because GitLab issue writes do not provide a universal native idempotency key.
baseUrl is your Jira Cloud tenant root without a trailing REST path. projectKey supplies the default project for creates and search.
Basic authentication uses the Atlassian account email and an API token, not the account password. OAuth 2.0 applications can provide a bearer token through the adapter's supported auth configuration.
Jira API tokens often span more projects than an individual tool needs. Run the client in a server boundary and use a dedicated account with the narrowest practical project permissions.
Jira does not update status like an ordinary field. The adapter reads available transitions for the issue, resolves the requested normalized or display state, and then invokes the matching transition ID.
If no unambiguous transition exists, preparation or commit fails instead of choosing a similarly named state.
| Work SDK | Jira Cloud | Behavior |
|---|---|---|
| description | ADF document | Plain text is converted conservatively. |
| comment | ADF document | The normalized body remains plain text. |
| priority | priority name / ID | Resolved against tenant metadata. |
| parentId | parent issue key | Supported when the issue type allows it. |
| kind | issue type | Maps task, bug, story, epic, and subtask. |
The receipt is an UpdateCommitResult. The adapter re-reads the issue revision before writing, but Jira's multi-request transition flow still has a race window and is reported as preflight concurrency.
Use a personal API key for a single workspace or an OAuth access token for an installed application. teamId provides the default team for creates and state resolution.
get accepts a Linear UUID or readable identifier such as ENG-123. Creates need a team from the adapter or input.project. List cursors are opaque GraphQL cursors and must be passed back unchanged.
State and label names are scoped by workspace and team. Resolve them through the adapter rather than hard-coding internal Linear IDs in an agent prompt.
| Work SDK | Linear |
|---|---|
| backlog | Workflow state type backlog |
| unstarted | Workflow state type unstarted |
| started | Workflow state type started |
| completed | Workflow state type completed |
| urgent / high / medium / low / none | Native priority 1–4 or 0 |
The normalized state is portable. stateName preserves the workspace's exact display name, such as “In review”.
Prepared changes include the current Linear issue and revision fingerprint. A final read blocks a stale plan before mutation; Linear does not expose an atomic compare-and-set for this adapter, so the guarantee remains preflight.
Subpath exports keep provider implementations independently tree-shakeable. All adapters return the same WorkAdapter contract.
| Capability | GitHub | GitLab | Linear | Jira | Azure DevOps |
|---|---|---|---|---|---|
| Create / update | Yes | Yes | Yes | Yes | Yes |
| Comments | Markdown | Markdown | Markdown | ADF | Markdown |
| Custom states | No | No | Yes | Yes | Yes |
| Priorities | No universal field | No universal field | Native | Native | 1–4 mapping |
| Multiple assignees | Yes | Opt-in | No | No | No |
| Parent links | No | No | Yes | Yes | Yes |
| Search | Not in adapter | REST search | GraphQL filters | JQL | WIQL |
| Concurrency | Readback revision | Readback revision | Readback revision | Readback revision | Native /rev test |
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.
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.
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 status changes are transitions, not ordinary field updates. The adapter discovers available transitions and converts conservative text content to Atlassian Document Format.
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.
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.
createWorkClientadapter is required. The default idempotency store is process-local memory. now exists for deterministic testing and should normally be omitted.
get(id, options?)Returns one normalized item or throws WorkNotFoundError. IDs are adapter-native: a GitHub issue number, Linear ID or identifier, Jira key, or Azure work-item ID.
list(input?, options?)Returns an opaque provider cursor. Never construct or parse cursors; pass nextCursor back unchanged.
prepareCreate(input)Plan a new item without writing it.prepareUpdate(id, input, options?)Read current state and calculate a changed-field diff.prepareComment(id, input, options?)Read the target and plan a comment.Create plans do not have an expected revision. Update and comment plans capture the current item and opaque revision.
commit(change, options?)Commit validates provider identity, fingerprint integrity, warning acknowledgement, idempotency state, and revision before calling the adapter. The receipt follows the prepared action: create plans return CreateCommitResult, updates return UpdateCommitResult, and comments return CommentCommitResult with a required comment.
If a mutation starts and the provider outcome becomes uncertain, Work SDK stores an ambiguous state and throws WorkAmbiguousCommitError. Reconcile the provider result before another write; never blind-retry that key.
| Type | Purpose |
|---|---|
WorkItem | Normalized item plus provider state name, opaque revision, URL, and optional raw payload. |
WorkComment | Normalized body, author, timestamps, and raw payload. |
PreparedWorkChange | Serializable, fingerprinted plan for one create, update, or comment. |
CommitResult | Discriminated union of create, update, and comment receipts with replay flag and commit time. |
CommitResultFor<T> | Maps a prepared change type to its exact action-specific receipt. |
WorkPage<T> | Items plus an optional opaque next cursor. |
WorkWarning | Structured provider limitation or lossy/ambiguous mapping notice. |
work.capabilities is an immutable snapshot. Inspect it when building tools or UIs so unsupported actions are absent rather than offered and rejected later.
optimisticConcurrency remains as a deprecated compatibility Boolean. New code should use the action-specific concurrency object.
IdempotencyStoreThe client prefixes keys with the provider. acquire must be atomic across every worker using the store; use a transaction, compare-and-swap, unique insert, or conditional put. A durable get followed by set is not sufficient.
WorkInFlightError; another worker owns the claim.WorkAmbiguousCommitError; reconcile before retrying.| Class | Code | Typical response |
|---|---|---|
WorkAuthenticationError | authentication | Refresh or replace credentials; do not blind-retry. |
WorkAuthorizationError | authorization | Request scope/permission or remove the action. |
WorkNotFoundError | not_found | Verify target and visibility. |
WorkRateLimitError | rate_limit | Retry after the supplied delay with jitter. |
WorkConflictError | conflict | Re-read, prepare a new plan, request approval again. |
WorkInFlightError | in_flight | Wait for the current claim owner, then reuse the same key. |
WorkAmbiguousCommitError | ambiguous | Reconcile provider state; never blind-retry. |
WorkUnsupportedError | unsupported | Change the tool schema or provider strategy. |
WorkValidationError | validation | Fix input; retrying unchanged input is wrong. |
WorkError | provider / network | Inspect cause and provider policy. |
retryAfterMs, add jitter, preserve the idempotency key.A timeout cannot prove whether the remote provider committed a write. Work SDK records that uncertainty explicitly and blocks another mutation until application reconciliation resolves it.
Log class, code, provider, status, retry delay, and a correlation ID. Treat details and cause as potentially sensitive because providers can echo field values or request context. Never log adapter options or authorization headers.
{group.label}
- {group.links.map(([label, href]) => ( - - {label} - - ))} -No documentation page found.
} -Docs / {breadcrumb}
-{description}
- {children} -{code}
-