Skip to main content
@antigenco/sdk is the typed client for Antigen Runs. It offers two entry points into the same API. Use antigen.agent(config).run(targets) when the model and Guardrails belong together as one assessment configuration. Use antigen.runs when your application owns the request fields, or when it is reconnecting to a Run it created earlier. An integration owns three things: an organization API key, an approved target, and durable storage for the Run ID. Antigen supplies the approved target list; you choose from it and record why the target is in scope. A Run ID is a locator rather than a credential, so store it alongside the assessment record and rely on organization permissions for every later read or operation.

Install

The SDK is ESM-only and requires Node 22 or later. It ships its own TypeScript declarations.

Authenticate

Pass an organization API key as the first argument. Keys begin with atg_sk_; read them from your secret source at startup and never commit or log them.
The atg_sk_ prefix identifies the credential kind, not its validity, expiry, or scope, so a shape check cannot tell you whether a key still works. The service answers that with a structured error carrying a requestId. Later examples on this page assume this antigen client and an approved target string already exist, so that each one shows only the call being described.

Quick start

This complete program picks an approved target, creates a Run, follows its events, and prints the first finding’s remediation. Save it as assess.ts and run it with npx tsx assess.ts.
The two files stand in for whatever durable storage your application already operates. The Run ID must be written as soon as creation succeeds, and an event sequence only after that event has been handled. Those two ordering rules are what make recovery deterministic.

Client

new Antigen

Constructs a client. The common form takes an API key; the object form is for callers that hold a user access token or need to reach a non-hosted environment.
The object form is the one to reach for when a value other than an API key varies:
Pass exactly one of apiKey and accessToken. Supplying both, neither, a blank credential, or an apiKey without the atg_sk_ prefix throws AntigenProtocolError from the constructor. baseUrl is validated the same way: it must be an http or https URL carrying no query, fragment, or embedded credentials. The client exposes antigen.runs for the Run collection and antigen.agent(config) for the assessment facade. Constructing a client performs no network request, so a well-formed but invalid credential is reported by the service on the first call, not here.

antigen.getApprovedTargets

Lists the targets approved for the caller’s organization. Call it before creating a Run.
Select a returned value unchanged. If creation later returns TARGET_NOT_APPROVED, read this list again rather than editing the rejected target. An empty list is an authorization question for your organization administrator, not an integration bug.

Create a Run

antigen.agent

Creates an assessment facade that keeps model configuration and Guardrails next to Run creation.
Each skills entry may be a .md file or a directory, which is walked in deterministic order. Symbolic links are rejected, empty files are rejected, and each Skill’s name is its filename without the extension, so names must be unique across the whole set. Treat these files as reviewed application input and keep credentials out of them.
Guardrails shape how the agent works. The approved target list is the enforced boundary. Keep one assessment configuration to one coherent objective.

agent.run

Creates a Run from the Agent’s configuration for one or more approved targets.
targets must be non-empty and every entry must come from getApprovedTargets. Invalid input, transport failures, and service rejections reject rather than returning a partial Run, so a resolved promise always carries a real run.id. Persist run.id immediately. If the create response is ambiguous, read that saved ID with runs.get before deciding whether another assessment is necessary. A second create is a new assessment record, never a retry.

runs.create

Creates a Run from request fields your application supplies directly. Use this form when the application, rather than an Agent configuration, owns the request.
Unlike agent.run, this form takes Skill content inline rather than reading local paths, so it works in runtimes without filesystem access. Pick one creation form per integration boundary.

Find a Run

runs.list

Reads a page of Runs visible to the caller’s organization.
runs are full Run objects, so you can act on one without a second read. Preserve nextCursor unchanged and pass it back only for the next page. Do not derive authorization, identity, or ordering from a cursor or a Run ID.

runs.get

Reads a known Run by its saved opaque ID. This is the entry point for every recovery path.
RUN_NOT_FOUND and authorization failures reject: the ID alone does not grant access. Read a saved Run before retrying any ambiguous create or lifecycle request.

Observe a Run

A Run separates the durable assessment record from what your caller has observed. run.current holds the last representation the client saw, without making a request. The methods below refresh it. Process evidence before advancing its saved checkpoint.

run.status

Reads and refreshes the latest durable representation of the Run.
RunState is a discriminated union on status, so the timestamps it carries depend on how far the Run has progressed: startedAt once running, stoppedAt when stopped, completedAt on a terminal state, and a failure object of { code, message } when status is failed. Read status after an ambiguous create, a lifecycle action, a local wait, or an event interruption, before deciding on the next operation.

run.events

Streams ordered events and resumes cleanly after a handled checkpoint.
A Run is itself async-iterable, so for await (const event of run) is shorthand for run.events() with no options.
Every event carries sequence, summary, timestamp, and an optional originating agent of planner, recon, executor, or system. Switch on type for the rest: The SDK reconnects a dropped stream on your behalf and recognizes exact duplicate replay within the most recent 256 events. Out-of-order or unknown older events are protocol errors rather than silent gaps. Persist event.sequence only after handling the event; saving first can skip unprocessed work, and never saving makes the same evidence look new after every interruption.

run.findings

Reads durable findings for the Run.
A completed Run can have no findings; that is a valid assessment result, not an integration failure. Treat findings as evidence for a human risk decision, and preserve proof and remediation with the assessment record. A local failure does not mean a finding was removed.

run.wait

Waits locally until the Run reaches completed, failed, or cancelled.
stopped is not wait-terminal, so a stopped Run keeps the wait running until the deadline. The deadline is local: on AntigenWaitTimeoutError, reconnect with runs.get and run.events rather than assuming the Run ended or calling run.cancel.

Guide a Run

run.send

Delivers scoped guidance to an assessment already under way, without changing its approved purpose.
content must be non-empty and stay inside the approved target and Guardrails. Prefer a specific, reviewable request over a broad change of purpose. If necessary work falls outside the approved scope, obtain authorization and create a separate assessment instead.

Control a Run

completed, failed, and cancelled are terminal. Use a lifecycle operation to express a decision, not to repair a local timeout. If one is rejected with INVALID_RUN_STATE, another transition already occurred: read the Run and choose an action valid for the observed state.

run.stop

Requests a reviewable pause, leaving the Run resumable.

run.resume

Requests continuation of a stopped Run you already hold.
Resuming does not re-evaluate target approval, so confirm the approved scope still applies first.

runs.resume

Resumes a stopped Run by ID and returns a Run object for it. Use this when the application has a saved ID but not a live Run, which is the usual case after a restart.
agent.resume(runId, options) is an equivalent alias on the Agent facade, for code that is already working through an Agent. It ignores the Agent’s model and Guardrails, because a resumed Run keeps the configuration it was created with.

run.cancel

Ends the assessment. cancelled is terminal.
Cancel only when ending the assessment is the intended business decision, never as a response to a local timeout or a dropped connection.

Request options

Every method accepts RequestOptions as its last argument. Both fields bound the caller’s own work and neither changes a Run that Antigen has already accepted.
Use a short request deadline for interactive actions and one that fits your job queue for background work. run.wait extends these with waitTimeoutMs and pollIntervalMs, and run.events extends them with after.

Errors

The SDK distinguishes local wait timeouts, protocol failures, and HTTP failures. Transport failures surface as the underlying fetch error.
A structured service error carries a stable code in its body. Retain the requestId with the saved Run ID: it lets support identify the failing request without exposing credentials. RUN_NOT_FOUND also answers a Run held by another organization, so it is not evidence that an ID was never issued. Branch on status for a code you do not recognize rather than matching the list exhaustively: the set can grow, and an unhandled code should not become a crash. AntigenHttpError is worth retrying when its status is 408, 429, or 5xx, and is not worth retrying otherwise. Creating a Run is the exception to retrying at all: there is no idempotency key, so a retried create that in fact succeeded leaves two Runs executing and billable. List Runs first.

Recover from an ambiguous result

When a create, lifecycle, or observation call fails, the local failure tells you what your caller knows. It does not establish what the Run did. Recovery is always the same shape:
  1. Read the saved Run ID from your durable store.
  2. Call runs.get, then run.status for its current state.
  3. Continue run.events strictly after the last sequence you finished handling.
  4. Read run.findings for durable remediation work.
Do not send a replacement create request because the first response was inconclusive, and do not call run.cancel because a wait expired. Both turn an unknown local state into a real change to the assessment record. Related concepts: Guides, Examples, HTTP API reference, and Reliability and security.