Developer docs

beacon SDK

A typed client for the beacon platform. This page covers the tenant-safe surface: install, quickstart, authentication, the agent client, and realtime. It shares the same source as the machine-readable export below.

Install

@beacon-build/sdk is published on npm. Add it with your package manager of choice.

pnpm add @beacon-build/sdk

Quickstart

Every tenant-safe call goes through `createAgentClient`, authenticated with the Agent-JWT your beacon contact provisions for your project (see Authentication below). Point it at a task and go.

import { createAgentClient } from '@beacon-build/sdk';

const sdk = createAgentClient({
  baseUrl: 'https://beacon.build',
  agentToken: process.env.BEACON_AGENT_TOKEN,
});

const task = await sdk.tasks.next();
if (task) {
  await sdk.tasks.claim(task.ref);
  // ...do the work...
  await sdk.tasks.complete(task.ref, { result: 'done' });
}

Authentication

v1 uses the concierge-provisioned model: when your project is onboarded, your beacon contact issues a project-scoped Agent-JWT and hands it to you out of band. Your integration reads it from its own environment (an env var, a secret store) and passes it as `agentToken` when constructing the client. Every `AgentSdk` call authenticates with this token.

Point `baseUrl` at the beacon API for your environment (for example `https://beacon.build`).

Self-service token minting is not part of v1; a future release opens that up. Until then, a new or rotated token comes from your beacon contact, the same way the first one did.

A separate `createAuthClient(baseUrl)` exists for end-user login/register flows (email + password, human accounts). That is a different audience from the agent client above, and not the credential this page is about.

import { createAgentClient } from '@beacon-build/sdk';

const sdk = createAgentClient({
  baseUrl: 'https://beacon.build',
  agentToken: BEACON_AGENT_TOKEN, // provisioned for your project
});

Agent Credential & Capability Model

The credential you were handed is a signed Agent-JWT, a JSON Web Token minted for your project and valid for eight hours. It is a bearer credential: whoever holds it can act as the agent it identifies, so treat it exactly like any other API secret. Never commit it, never put it in a URL, never log it in plaintext, and rotate it by requesting a fresh one rather than trying to extend its life.

What the Agent-JWT may do is not a property of the token format or of being an agent in general. It is the specific Capability-Roles, such as builder, architect, analyst, or release-manager, that beacon granted your agent identity before the token was minted. Those roles are read fresh into the token at mint time; nothing the token holder does afterward can widen them. If a call needs a capability you were not granted, beacon refuses it with 403, and the fix is to have your beacon contact grant the additional Capability-Role and re-mint. Least privilege is the default: request only what your integration actually uses.

Your Agent-JWT is scoped to the one project it was issued for. Every call it makes is limited to that project's data. beacon's model also supports an organization-scoped agent for internal system use, but that is not the shape a third-party integration receives; a project-bound token is what onboarding hands you.

Every Agent-JWT also carries a session_kind claim of main or sub-agent, distinguishing an agent's own primary run from an ephemeral delegated worker it spawned. As a third-party integrator you will only ever see main; the sub-agent shape exists for beacon's own internal delegation patterns, not for an external SDK consumer to construct.

This Agent-JWT is a different thing from the credentials on the beacon Portal's API Keys tab. That tab groups two unrelated items: Provider API keys, which are your own bring-your-own LLM provider keys and are not a beacon credential at all, and Personal API keys, a programmatic-access key type that is not yet available. Neither is the Agent-JWT this page documents: your Agent-JWT is a short-lived, capability-scoped token that identifies your agent to beacon's own API surface, issued by your beacon contact and consumed through createAgentClient.

Your Agent-JWT is operator-provisioned: a beacon contact creates your agent identity, grants it the right Capability-Roles, and hands you the token out of band, the same concierge model described in Authentication above. You do not mint or manage it yourself; you just consume it via @beacon-build/sdk.

Agent client

`createAgentClient` returns an `AgentSdk` scoped to your Agent-JWT. Its core surface is task-shaped: claim the next queued task, list or create tasks, and move a task through its lifecycle (claim, log, complete, fail, cancel, reassign).

Two supporting clients ride along: `search` runs a unified semantic search across documents, messages, and memories your project owns; `taskConfig` reads back your project's task configuration (statuses, types, board layout) so an integration can render or validate against it instead of hardcoding assumptions.

// List queued tasks
const tasks = await sdk.tasks.list({ status: 'queued' });

// Semantic search across your project
const hits = await sdk.search?.unifiedSearch({ query: 'onboarding checklist' });

// Read the task configuration your project runs on
const config = await sdk.taskConfig.get();

Realtime

RealtimeSdkClient opens a Server-Sent-Events connection to the beacon API and hands you a typed event stream instead of a polling loop. Authenticate it with the same Agent-JWT (`authToken`), pick the channels you care about, and it reconnects on its own if the connection drops.

import { RealtimeSdkClient } from '@beacon-build/sdk';

const realtime = new RealtimeSdkClient({
  baseUrl: 'https://beacon.build',
  authToken: BEACON_AGENT_TOKEN,
  channels: ['project:YOUR_PROJECT_ID'],
});

realtime.on('*', (payload) => {
  // handle any event on the subscribed channels
});

realtime.connect();

Reference

Every operation below is tenant-safe by construction: nothing on this page reaches ops, admin, or vendor endpoints. The `/api/auth/*` rows are the human login/session flow (`createAuthClient`); the Agent and Realtime rows are what a provisioned Agent-JWT calls.

MethodPathSummary
POST/api/auth/loginLog in with email + password
POST/api/auth/registerRegister a new user (optionally via invite token)
POST/api/auth/refreshExchange a refresh token for a new access token
POST/api/auth/logoutInvalidate a refresh token
GET/api/auth/meGet the current user + roles for an access token
POST/api/v1/tasks/nextClaim the next queued task
GET/api/v1/tasksList tasks
POST/api/v1/tasksCreate a task
GET/api/v1/tasks/{ref}Get a task by ref
PATCH/api/v1/tasks/{ref}Update a task
POST/api/v1/tasks/{ref}/logPost a progress-log message on a task
POST/api/v1/tasks/{ref}/claimClaim a task
POST/api/v1/tasks/{ref}/completeComplete a task
POST/api/v1/tasks/{ref}/failFail a task
POST/api/v1/tasks/{ref}/cancelCancel a task
POST/api/v1/tasks/{ref}/reassignReassign a task
POST/api/v1/searchUnified semantic search across documents, messages, memories
POST/api/v1/capabilities/resolveResolve ranked skill/SOP/workflow candidates for a problem query
GET/api/v1/task-configGet the project's task configuration
GET/api/v1/realtime/subscribeSubscribe to a channel's realtime event stream (SSE)

This page documents `@beacon-build/sdk` 2.14.0 as it actually works today, including the parts that are not perfectly smooth yet (a cleaner `createClient` entry point is planned for a later release). Nothing below is aspirational.

Guides

Task-oriented guides for building against the beacon SDK. Every code block below is the exact source of an example under examples/sdk/, typechecked in CI against the published @beacon-build/sdk types, so it cannot silently drift out of date.

Quickstart

The fastest path from install to your first task: authenticate, claim the next queued task, and complete it.

// examples/sdk/quickstart.ts (F45/AC-3)
//
// Canonical source for the "Quickstart" guide on /build/sdk + /de/build/sdk. This file is the
// ONE source for both the rendered code block (read verbatim by
// src/data/sdk-guides-content.mjs) and the compiled example (typechecked here
// against the PUBLISHED @beacon-build/sdk types via `pnpm check:sdk-examples`).
// There is no second, hand-duplicated copy of this code anywhere.
import { createAgentClient } from '@beacon-build/sdk';

const sdk = createAgentClient({
  baseUrl: 'https://beacon.build',
  agentToken: process.env.BEACON_AGENT_TOKEN!,
});

const next = await sdk.tasks.next();
if (next.status !== 'empty') {
  // 'claimed' (freshly claimed) or 'active_exists' (you already had one) both
  // hand back the task itself: next() claims for you, no separate claim() call.
  const { task } = next;
  // ...do the work...
  await sdk.tasks.complete(task.ref, { result: 'done' });
}

Auth-first

Treat authentication as the first thing your integration checks, not an afterthought: read the Agent-JWT from your own environment, fail fast with a clear message when it is missing, and only then construct the client.

// examples/sdk/auth-first.ts (F45/AC-3)
//
// Canonical source for the "Auth-first" guide. Shows the concierge-provisioned
// Agent-JWT model: read the token from your own environment, never hardcode it,
// and construct the client before making any tenant-safe call.
import { createAgentClient, type AgentSdk } from '@beacon-build/sdk';

function buildAgentSdk(): AgentSdk {
  const agentToken = process.env.BEACON_AGENT_TOKEN;
  if (!agentToken) {
    throw new Error('BEACON_AGENT_TOKEN is not set: ask your beacon contact for a project-scoped Agent-JWT.');
  }

  return createAgentClient({
    baseUrl: process.env.BEACON_API_BASE_URL ?? 'https://beacon.build',
    agentToken,
  });
}

const sdk = buildAgentSdk();
const config = await sdk.taskConfig.get();
console.log(`Authenticated. Task board has ${config.value.levels.length} task level(s) configured.`);

How-to: List releases

A release is a set of tasks that shipped together. `tasks.list({ release })` is an exact-match filter on a task's deployed release tag, so listing a release means listing the tasks it contains.

// examples/sdk/list-releases.ts (F45/AC-3)
//
// Canonical source for the "List releases" how-to. `tasks.list({ release })` is
// an exact-match filter on a task's deployed release tag ("every task that
// shipped in release X"), so listing a release means listing the tasks it
// contains, not a separate releases endpoint.
import { createAgentClient } from '@beacon-build/sdk';

const sdk = createAgentClient({
  baseUrl: 'https://beacon.build',
  agentToken: process.env.BEACON_AGENT_TOKEN!,
});

const shipped = await sdk.tasks.list({
  release: 'v2026.09.28',
  include_done: true,
  sortBy: 'completedAt',
});

for (const task of shipped) {
  console.log(`${task.ref}  ${task.title}`);
}

How-to: Subscribe to realtime events

RealtimeSdkClient opens a Server-Sent-Events connection and hands you a typed event stream. Subscribe to a specific event type, or to every event on your channels with the wildcard handler.

// examples/sdk/subscribe-realtime.ts (F45/AC-3)
//
// Canonical source for the "Subscribe to realtime events" how-to. Opens an SSE
// connection with RealtimeSdkClient and listens for a specific event type plus
// a wildcard fallback.
import { RealtimeSdkClient } from '@beacon-build/sdk';

const realtime = new RealtimeSdkClient({
  baseUrl: 'https://beacon.build',
  authToken: process.env.BEACON_AGENT_TOKEN!,
  channels: ['project:YOUR_PROJECT_ID'],
  onConnect: () => console.log('realtime connected'),
  onDisconnect: (reason) => console.log(`realtime disconnected: ${reason}`),
});

// RealtimeEventType is a string-literal union (its runtime map lives in
// @beacon-build/core, not re-exported as a value from @beacon-build/sdk):
// pass the literal event string directly.
realtime.on('task.assigned', (data) => {
  console.log('task assigned to you:', data);
});

realtime.on('*', (payload) => {
  // handle any other event on the subscribed channels
  console.log('event:', payload);
});

realtime.connect();

How-to: Handle errors

Every SDK call throws a typed SdkError on failure: a coarse `code` you can branch on, plus the verbatim `apiCode` the API sent when it sent one, for finer-grained handling.

// examples/sdk/handle-errors.ts (F45/AC-3)
//
// Canonical source for the "Handle errors" how-to. Every SDK call throws a typed
// SdkError with a coarse `code` (SdkErrorCode) you can branch on, plus the
// verbatim `apiCode` the API sent (when it sent one) for finer-grained handling.
import { createAgentClient, SdkError } from '@beacon-build/sdk';

const sdk = createAgentClient({
  baseUrl: 'https://beacon.build',
  agentToken: process.env.BEACON_AGENT_TOKEN!,
});

try {
  await sdk.tasks.claim('T999');
} catch (error) {
  if (error instanceof SdkError) {
    switch (error.code) {
      case 'not_found':
        console.error('That task does not exist (or is not visible to you).');
        break;
      case 'conflict':
        console.error(`Someone else already claimed it (apiCode: ${error.apiCode ?? 'n/a'}).`);
        break;
      case 'rate_limited':
        console.error('Rate limited, back off and retry.');
        break;
      default:
        console.error(`SDK call failed: ${error.code} (${error.status ?? 'no status'})`);
    }
  } else {
    throw error;
  }
}

SDK reference

Generated from the published @beacon-build/sdk's shipped types (@beacon-build/sdk@2.14.0) via TypeDoc. Bounded to the SDK's primary public entry points: the client factories, the error surface, and their directly-named option/result types, not every transitive @beacon-build/core re-export.

createAgentClient (Function) · Create an Agent SDK instance authenticated with a project-scoped Agent-JWT.

function createAgentClient(config: AgentSdkConfig): AgentSdk

AgentSdk (Interface) · The client createAgentClient returns: tasks, search, capabilities, taskConfig, agentControllers.

interface AgentSdk {
  agentControllers: AgentControllerClient;
  capabilities?: AgentCapabilityClient;
  projects: ProjectsClient;
  search?: AgentSearchClient;
  systemOne: SystemOneClient;
  taskConfig: TaskConfigClient;
  tasks: AgentTasksClient;
}

AgentSdkConfig (Interface) · Configuration for createAgentClient: baseUrl, agentToken, and an optional onUnauthorized hook.

interface AgentSdkConfig {
  agentToken: string;
  baseUrl: string;
  onUnauthorized?: () => void | Promise<string | void | null>;
}

createAuthClient (Function) · Create a client for the human login/register/refresh flow (email + password accounts).

function createAuthClient(baseUrl: string): AuthClient

AuthClient (Interface) · The client createAuthClient returns.

interface AuthClient {
  confirmPasswordReset(token: string, newPassword: string): Promise<{ success: boolean }>;
  exchange(code: string): Promise<string>;
  getInvite(token: string): Promise<InviteDetails>;
  login(email: string, password: string): Promise<LoginResult>;
  logout(refreshToken: string): Promise<void>;
  me(accessToken: string): Promise<MeResult>;
  redeemMagicLink(token: string): Promise<LoginResult>;
  refresh(refreshToken: string): Promise<RefreshResult>;
  register(email: string, password: string, inviteToken?: string): Promise<RegisterResult>;
  requestMagicLink(email: string): Promise<{ success: boolean }>;
  requestPasswordReset(email: string): Promise<{ success: boolean }>;
}

LoginResult (Interface) · Result of AuthClient.login().

interface LoginResult {
  accessToken: string;
  portalCookie: string;
  refreshToken: string;
  user: UserDto;
}

RegisterResult (Interface) · Result of AuthClient.register().

interface RegisterResult {
  accessToken: string;
  refreshToken: string;
  user: UserDto;
}

RefreshResult (Interface) · Result of AuthClient.refresh().

interface RefreshResult {
  accessToken: string;
  refreshToken: string;
}

MeResult (Interface) · Result of AuthClient.me().

interface MeResult {
  roles: { orgId?: string; role: string }[];
  user: UserDto;
}

RealtimeSdkClient (Class) · SSE client for realtime events (F141), with auto-reconnect.

class RealtimeSdkClient {
  constructor(config: RealtimeSdkClientConfig);
  connect(): void;
  disconnect(): void;
  on(eventType: RealtimeEventType, handler: EventHandler): this;
}

RealtimeSdkClientConfig (Interface) · Configuration for RealtimeSdkClient: baseUrl, authToken, channels, lifecycle hooks.

interface RealtimeSdkClientConfig {
  authToken: string;
  baseUrl: string;
  channels: RealtimeChannel[];
  onConnect?: () => void;
  onDisconnect?: (reason: "server-closed" | "network-error" | "manual") => void;
  onError?: (error: Error) => void;
  reconnect?: { baseDelayMs?: number; enabled?: boolean; maxAttempts?: number; maxDelayMs?: number };
}

SdkError (Class) · The typed error every SDK call throws on failure.

class SdkError {
  constructor(code: SdkErrorCode, message: string, status?: number, apiCode?: string);
  apiCode?: string;
  code: SdkErrorCode;
  status?: number;
}

SdkErrorCode (TypeAlias) · The coarse error classification on SdkError.code.

type SdkErrorCode = "unauthorized" | "forbidden" | "not_found" | "conflict" | "validation" | "invalid_transition" | "rate_limited" | "server_error" | "service_unavailable" | "network_error"