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 * * * *" },
});
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:
| Kind | Format |
|---|
connector, model | snake_case (my_source) |
worker, app | kebab-case, starts with a letter (my-worker) |
| everything else | lowercase letters, digits, -, _ |