Skip to main content
Every Cargo resource has a define* builder. Each returns a handle whose outputs are deferred tokens; you wire resources together by passing one handle’s token into another’s spec.

Connectors

import { defineConnector, secret } from "@cargo-ai/cdk";

// Config-based: pass credentials via secret().
export const hubspot = defineConnector("hubspot", {
  integration: "hubspot",
  config: { apiKey: secret("HUBSPOT_API_KEY") },
});

// OAuth / already-authenticated: adopt the existing connector by slug.
export const openai = defineConnector("open_ai", {
  integration: "openAi",
  adopt: true,
});
Creating a connector auto-creates a dataset; models source from it via connector.datasetUuid.

Models

import { defineModel } from "@cargo-ai/cdk";

export const contacts = defineModel("contacts", {
  datasetUuid: hubspot.datasetUuid, // token
  extractSlug: "fetchRecords",
  config: { objectId: "contacts" },
  schedule: { type: "cron", cron: "0 * * * *" },
});

Tools

A tool is backed by a workflow (defineWorkflow). The workflow body is parsed and compiled — it is never executed at build time.
import { defineTool, defineWorkflow } from "@cargo-ai/cdk";
import { z } from "zod";

const flow = defineWorkflow(
  "enrich-contact",
  { input: z.object({ email: z.string() }), output: z.object({ company: z.string() }) },
  ({ input, ai }) => ({ company: ai(`What company owns ${input.email}?`) }),
);

export const enrich = defineTool("enrich", {
  workflow: flow,
  emojiSlug: "mag",
  triggers: [{ cron: "0 9 * * 1", name: "Weekly" }],
});

Agents

Agents reference an LLM connector, data models, tools, sub-agents and connector actions — all by uuid token.
import { defineAgent } from "@cargo-ai/cdk";

export const sdr = defineAgent("sdr", {
  color: "blue",
  connectorUuid: openai.uuid,
  languageModel: "gpt-4o",
  systemPrompt: "Qualify inbound leads.",
  capabilities: ["webSearch", "memory"],
  models: [{ uuid: contacts.uuid, readOnly: true }],
  tools: [{ uuid: enrich.uuid, waitUntilFinished: true }],
  subAgents: [{ uuid: enricher.uuid, isBulkAllowed: false }],
  connectorActions: [{ integration: "hunter", actionSlug: "emailFinder" }],
});
tools, subAgents and connectorActions all accept the same per-call options: name, description, isBulkAllowed, and waitUntilFinished (connector actions omit waitUntilFinished).

Plays

A play runs over a data model and emits runs as its rows change. It can carry a per-row workflow, deployed as its release.
import { definePlay } from "@cargo-ai/cdk";

export const onboarding = definePlay("onboarding", {
  modelUuid: contacts.uuid,
  changeKinds: ["added", "updated"],
  runCreationRule: "always",
  schedule: { type: "realtime" },
});

MCP servers

An MCP server bundles tools, agents and data-model resources behind one endpoint — the same rich refs as an agent.
import { defineMcpServer } from "@cargo-ai/cdk";

export const crm = defineMcpServer("crm", {
  tools: [{ uuid: enrich.uuid }],
  agents: [{ uuid: sdr.uuid }],
  models: [{ uuid: contacts.uuid, readOnly: true }],
});

Folders & files

import { defineFolder, defineFile } from "@cargo-ai/cdk";

// Folders are per-kind (a "model" folder and an "agent" folder are separate).
export const modelsFolder = defineFolder("crm", { kind: "model", name: "CRM" });

export const playbook = defineFile("playbook", {
  path: new URL("./playbook.md", import.meta.url).pathname,
});

Workers & apps

defineWorker/defineApp deploy a built bundle directory. The CDK validates the required files exist at define time.
import { defineWorker, defineApp } from "@cargo-ai/cdk";

// worker bundle root needs: index.js + manifest.json + package.json + package-lock.json
export const webhook = defineWorker("webhook", {
  path: new URL("./webhook", import.meta.url).pathname,
});

// app bundle root needs: index.html + package.json + package-lock.json (a Vite app)
export const dashboard = defineApp("dashboard", {
  path: new URL("./dashboard", import.meta.url).pathname,
});
The hosting build runs npm ci then esbuild (workers) / vite build (apps) — it does not transpile TypeScript. A worker bundle must ship a built index.js.

Slug rules

Slugs are validated at define time to match what each endpoint enforces, so a bad slug fails in plan rather than mid-deploy:
KindFormat
connector, modelsnake_case (my_source)
worker, appkebab-case, starts with a letter (my-worker)
everything elselowercase letters, digits, -, _