Forge
How it works

The harness that ships your customer's idea.

Your customer describes what they want. The build-time agent interprets the intent, writes the extension against your tools, validates it, and ships it — sandboxed, scoped to one customer, only able to touch what you've declared.

Build time vs. runtime

Two phases. One load-bearing distinction.

Build time

Your customer asks for a feature. Your trigger forwards their intent to Forge with subject context. The build-time agent writes the extension against the tools you've exposed, validates it against your registry, and ships it.

Runtime

The shipped extension lives in a sandboxed namespace, scoped to one customer. Triggers fire — your events, your crons — and the extension calls your APIs over plain HTTP using namespace-scoped secrets.

The agent never runs at runtime. The extension never invokes capabilities at runtime. That separation is how the blast radius of any one extension stays bounded by what you declared. See how isolation works →

The build-time loop

Codegen, validate, retry, ship.

The build-time agent runs the loop most platforms can't build for themselves: a system prompt aware of the runtime contract, type-checking against your tools, trigger / event-type validation against your catalog, synthetic dry-run with retry-on-error, and an eval harness that catches regressions as models drift.

1
Intent in

Your trigger surface posts the customer's request, plus subject context.

2
Codegen

The agent writes extension code against the tools your sources expose.

3
Validate

Type-check, tool-existence check, trigger / event-type check, dry-run.

4
Ship

Working extension lands in your product, ready for your customer to review and run.

What your platform calls

Four integration points. That's the SDK.

The harness is what Forge runs. Below is what your platform calls to wire it in.

01
Subjects + scoped tokens

Scope every extension to one of your customers

Upsert a subject when one of your customers logs in. A subject is whatever isolation unit your platform wants — a tenant, an end-user, a project. Forge treats it as an opaque scoping ID. Mint a session token scoped to that subject; the build-time agent uses it to call Forge's MCP and can only build or manage extensions for that subject.

const forge = new Forge({
  workspaceId: "ws_acme",
  apiKey: process.env.FORGE_API_KEY,
});

await forge.subjects.upsert({
  externalId: "tenant_12345",
  displayName: "Globex Co.",
  metadata: { plan: "pro" },
});

const sessionToken = await forge.tokens.createSubjectScoped({
  subjectExternalId: "tenant_12345",
  permissions: ["extensions:create", "extensions:list", "extensions:pause"],
  ttlSeconds: 3600,
});
02
Sources + capability registry

Your tools, auto-discovered. Bounds enforced at build time.

Point Forge at your existing MCP server, OpenAPI, or GraphQL endpoint. Forge introspects it and exposes only those operations to the build-time agent — and the agent can never reference a tool that isn't in your registry. When the agent invokes one, Forge signs the dispatch with HMAC and includes the subject in a signed header, so your server knows whose context the call is in. Forge holds no per-subject host credentials. Runtime extension code talks to your APIs over plain HTTP using namespace-scoped secrets, so the blast radius of any one extension is bounded by what those secrets allow.

// Primary path: point Forge at your MCP server.
// Forge introspects it and surfaces every tool to the
// build-time agent.
await forge.sources.register({
  kind: "MCP",
  name: "Acme platform tools",
  url: "https://api.acme.com/mcp",
});

// Fallback: declare a single capability manually for
// hosts that can't run an MCP server.
await forge.capabilities.register({
  name: "send_slack_message",
  description: "Post a message to an approved Slack channel",
  inputSchema: { /* ... */ },
  handlerUrl: "https://api.acme.com/forge/cap/send_slack",
});
03
Review before activation

Your customer sees the extension before it runs

Generated extensions don't go live on their own. Your platform fetches the pending list and renders a review screen — branded, placed where it makes sense in your product (modal, inbox item, settings page). Your customer approves, edits, or rejects. Forge ships no opinionated review UI; the screen lives in your product, not ours.

const pending = await forge.extensions.listPendingApproval({
  subjectExternalId: "tenant_12345",
});

// pending[0]:
// {
//   id, name, description,
//   triggers: [{ kind: "event", eventType: "support_ticket.created" }],
//   capabilities: ["get_customer", "send_slack_message"],
//   secretsRequired: ["SLACK_WEBHOOK_URL"],
// }

await forge.extensions.approve(pending[0].id);
// or .edit(...) / .reject(...)
04
Event delivery

Fire events; Forge dispatches to subscribed extensions

Some triggers are crons — Forge runs them. Others are host events. You declare an event-type catalog up front; extensions can only subscribe to types in the catalog. When something happens in your product, you fire an event at Forge and we fan out to extensions subscribed to that event type for that subject.

await forge.events.deliver({
  subjectExternalId: "tenant_12345",
  eventType: "support_ticket.created",
  payload: { ticketId: "abc123", customerId: "cust_42" },
});
What Forge is not
  • A chat product. You bring the trigger surface; Forge accepts intent over an API and returns drafts.
  • A workflow builder. Extensions are written by the build-time agent, not by users dragging boxes.
  • A model vendor. BYO key or pay through us; we don't run models from scratch.
  • An embedded UI kit. You render the dashboard, approval flow, and run logs against the headless API.
  • A general agent platform. Forge is opinionated for one job: scoped, durable, sandbox-safe extensions for your customers.
Add a codegen extension layer to your platform.
Pilots are open with a small group of vertical SaaS partners.
Request access