Skip to main content
The @tangogroup/forge-sdk package provides a typed TypeScript client for the full Forge Platform API. It uses native fetch with zero runtime dependencies and works in Node.js, browsers, and edge runtimes.

📦 Installation

npm install @tangogroup/forge-sdk

🚀 Quick Start

import { ForgeClient, ForgeApiError } from "@tangogroup/forge-sdk";

const forge = new ForgeClient({
  baseUrl: "https://forge.gloo.ai",
  apiKey: process.env.FORGE_API_KEY!,
});

// List all agents
const { data: agents, meta } = await forge.listAgents();
console.log(`Found ${agents.length} agents (requestId: ${meta.requestId})`);

// Get a specific agent
const { data: agent } = await forge.getAgent("agent_abc123");
console.log(`Agent: ${agent.name} (${agent.tier})`);

⚙️ Initialization

The ForgeClient constructor accepts a base URL and an API key.
import { ForgeClient } from "@tangogroup/forge-sdk";

const forge = new ForgeClient({
  baseUrl: "https://forge.gloo.ai",
  apiKey: "forge_sk_abc123...",
});
baseUrl
string
required
The root URL of your Forge deployment. Do not include a trailing slash.
apiKey
string
required
A Forge API key with the scopes required for the methods you intend to call.
Never hardcode API keys in source code. Use environment variables or a secrets manager.

📋 Response Format

Every method returns a Promise that resolves to a response object with data and meta fields.
const response = await forge.listAgents();

// response.data  — the payload (Agent[] in this case)
// response.meta  — { requestId: string, hasMore?: boolean, nextCursor?: string | null }
For list endpoints, meta.hasMore indicates whether more results are available, and meta.nextCursor provides the cursor for the next page.

📋 Client Methods

Agents (v1)

V1 agent endpoints return the gateway-layer shape — useful when you need deployment status, gateway bindings, and runtime capabilities. For the definition-layer shape (purpose, governance, version), use the V2 methods.

listAgents

List all agents registered on the platform.
// List all agents
const { data: agents } = await forge.listAgents();

// Filter by gateway
const { data: gatewayAgents } = await forge.listAgents({ gatewayId: "gw_openclaw" });
gatewayId
string
Optional. Filter to agents deployed on a specific gateway.

getAgent

Get detailed information about a specific agent.
const { data: agent } = await forge.getAgent("agent_abc123");

console.log(agent.name);       // "Code Reviewer"
console.log(agent.tier);       // "standard"
console.log(agent.skills);     // ["code-review", "testing"]
console.log(agent.capabilities); // { streaming: true, ... }

transitionAgentStage

Transition an agent’s lifecycle stage. Valid stages: draft, active, suspended, archived.
const { data: result } = await forge.transitionAgentStage(
  "agent_abc123",
  "active",
  "Passed review and ready for production"
);

console.log(result.status); // "completed" or "pending_approval"
console.log(result.from);   // "draft"
console.log(result.to);     // "active"
If governance policies require approval for the transition, the status will be "pending_approval" and the response will include an approvalId.

getAgentLifecycleHistory

Get the lifecycle transition history for an agent.
const { data: history } = await forge.getAgentLifecycleHistory("agent_abc123", 10);

console.log(history.currentStage); // "active"
for (const t of history.transitions) {
  console.log(`${t.from} -> ${t.to} (${t.event}) by ${t.actor}`);
}

Agents (v2)

V2 agent endpoints return the definition-layer shape with richer metadata.

listAgentsV2

const { data: agents } = await forge.listAgentsV2();

getAgentV2

const { data: agent } = await forge.getAgentV2("agent_abc123");

console.log(agent.purpose);
console.log(agent.version);
console.log(agent.governance);

deployAgent

Deploy an agent to a specific gateway.
const { data: result } = await forge.deployAgent(
  "agent_abc123",
  "gw_openclaw",
  { model: "anthropic/claude-sonnet-4-20250514" } // optional overrides
);

console.log(result.deploymentId);

undeployAgent

Remove an agent deployment from a gateway.
const { data: result } = await forge.undeployAgent("agent_abc123", "gw_openclaw");
console.log(result.status); // "undeployed"

Runs

listRuns

List workflow runs with optional filters.
// List recent runs
const { data: runs } = await forge.listRuns();

// Filter by type with a limit
const { data: workflowRuns } = await forge.listRuns({
  runType: "workflow",
  limit: 10,
});

for (const run of workflowRuns) {
  console.log(`${run.id}: ${run.status} (${run.totalTokens ?? 0} tokens)`);
}
runType
string
Optional. Filter by run type.
limit
number
Optional. Maximum results to return. Range: 1-100. Default: 25.

getRun

Get detailed information about a specific run, including its steps.
const { data: run } = await forge.getRun("run_xyz789");

console.log(`Status: ${run.status}`);
console.log(`Steps: ${run.steps.length}`);

for (const step of run.steps) {
  console.log(`  ${step.stepId}: ${step.status} (${step.totalTokens ?? 0} tokens)`);
}

Events

listEvents

Query platform events with compound filters and cursor-based pagination.
const { data: events, meta } = await forge.listEvents({
  since: "2026-04-01T00:00:00Z",
  category: ["lifecycle", "error"],
  severity: ["error", "critical"],
  limit: 50,
});

for (const event of events) {
  console.log(`[${event.severity}] ${event.displayLabel}`);
}

// Paginate
if (meta.hasMore && meta.nextCursor) {
  const { data: nextPage } = await forge.listEvents({
    since: "2026-04-01T00:00:00Z",
    cursor: meta.nextCursor,
  });
}

getEventSummary

Get aggregated event counts broken down by category, severity, and source.
const { data: summary } = await forge.getEventSummary({
  since: "2026-04-01T00:00:00Z",
  agentId: "agent_abc123", // optional scope
});

console.log(`Total events: ${summary.total}`);
console.log(`By severity:`, summary.bySeverity);
console.log(`By category:`, summary.byCategory);

Cost

listCost

Query cost aggregates with optional filters.
const { data: cost } = await forge.listCost();

Keys

createKey

Create a new API key with specific scopes.
const { data: key } = await forge.createKey({
  scopes: ["agents:read", "runs:read"],
  label: "CI pipeline",
  expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days
});
The full API key value is only returned once in the creation response. Store it securely — it cannot be retrieved again.

listKeys

List all API keys for the current interface.
const { data: keys } = await forge.listKeys();

for (const key of keys) {
  console.log(`${key.label}: ${key.scopes.join(", ")}`);
}

revokeKey

Revoke an API key by ID. Revoked keys immediately stop working.
await forge.revokeKey("key_abc123");

Skills

listSkills

List all skills in the skill catalog.
const { data: skills } = await forge.listSkills();

for (const skill of skills) {
  console.log(`${skill.name} (${skill.status}) - ${skill.description}`);
}

getSkill

Get a specific skill by ID.
const { data: skill } = await forge.getSkill("skill_code_review");

Models

listModels

List all models in the model catalog.
const { data: models } = await forge.listModels();

for (const model of models) {
  console.log(`${model.displayName} (${model.provider}) - ctx: ${model.contextWindow}`);
}

getModel

Get a specific model by ID.
const { data: model } = await forge.getModel("anthropic/claude-sonnet-4-20250514");

Workflows

listWorkflows

List all workflow definitions.
const { data: workflows } = await forge.listWorkflows();

for (const wf of workflows) {
  console.log(`${wf.name} v${wf.currentVersion} (${wf.status})`);
}

getWorkflow

Get a specific workflow by ID or name.
const { data: workflow } = await forge.getWorkflow("vendor-onboarding");

Budgets

getBudgetStatus

Get budget status across all scopes.
const { data: budgets } = await forge.getBudgetStatus();

for (const budget of budgets) {
  console.log(
    `${budget.scope}: $${(budget.usedCents / 100).toFixed(2)} / $${(budget.budgetCents / 100).toFixed(2)} (${budget.percentUsed.toFixed(1)}%)`
  );
}

Evals

listEvals

List evaluation sets.
const { data: evals } = await forge.listEvals();

getEval

Get an evaluation set by ID.
const { data: evalSet } = await forge.getEval("eval_abc123");

listEvalRuns

List runs for a specific evaluation set.
const { data: runs } = await forge.listEvalRuns("eval_abc123");

❌ Error Handling

All client methods throw ForgeApiError when the API returns a non-2xx response. The error object includes the HTTP status, the machine-readable error code, the response body, and the request metadata.
import { ForgeClient, ForgeApiError } from "@tangogroup/forge-sdk";

const forge = new ForgeClient({
  baseUrl: "https://forge.gloo.ai",
  apiKey: process.env.FORGE_API_KEY!,
});

try {
  const { data: agent } = await forge.getAgent("nonexistent_id");
} catch (error) {
  if (error instanceof ForgeApiError) {
    console.error(`Status: ${error.status}`);        // 404
    console.error(`Code: ${error.code}`);             // "not_found"
    console.error(`Message: ${error.message}`);       // "Agent with ID '...' does not exist."
    console.error(`Request ID: ${error.meta?.requestId}`);
  }
}

ForgeApiError Properties

PropertyTypeDescription
statusnumberHTTP status code (400, 401, 403, 404, 500)
codestringMachine-readable error code (unauthorized, forbidden, not_found, bad_request, internal_error)
messagestringHuman-readable error description
metaobject | nullResponse metadata including requestId

Common Error Patterns

try {
  await forge.deployAgent(agentId, gatewayId);
} catch (error) {
  if (error instanceof ForgeApiError) {
    switch (error.code) {
      case "unauthorized":
        // API key is missing or revoked
        break;
      case "forbidden":
        // Key lacks agents:write scope
        break;
      case "not_found":
        // Agent or gateway does not exist
        break;
      case "bad_request":
        // Invalid request parameters
        break;
      case "internal_error":
        // Server error -- retry or report with requestId
        break;
    }
  }
}

🏷️ TypeScript Types

The SDK exports all response types for use in your application code.
import type {
  Agent,
  Run,
  RunDetail,
  RunStep,
  HealthStatus,
  PlatformEvent,
  EventSummary,
  SkillSummary,
  ModelSummary,
  WorkflowSummary,
  BudgetStatus,
  LifecycleTransitionResult,
  LifecycleHistory,
} from "@tangogroup/forge-sdk";

🚀 Next Steps

API Reference

Full endpoint documentation with request/response schemas.

MCP Server

Give AI agents direct access to Forge through the Model Context Protocol.