Skip to main content

SDK & Runtime API

The broods package exposes a typed TypeScript SDK for invoking agents at runtime. You can also call the HTTP endpoints directly with curl or any HTTP client. A Python SDK is planned for a future release.

Installation

npm install broods
# or
bun add broods

Authentication

Runtime calls use the environment runtime API key (not your dashboard login token). After your first broods deploy, the CLI writes BROODS_API_KEY to .env.local. The SDK loads it automatically, or you can pass it explicitly:

import { BroodsClient } from "broods";

const client = new BroodsClient();
// Loads BROODS_API_KEY from .env.local automatically

Or explicitly:

const client = new BroodsClient({
apiKey: process.env.BROODS_API_KEY,
});

For self-hosted deployments, point the client at your own core service:

const client = new BroodsClient({
baseUrl: "https://your-deployment.lambda-url.us-east-1.on.aws",
apiKey: "fp_env_...",
});

Invoke an Agent

Sync Run (accumulate text)

import { api } from "./broods/_generated/api";

const client = new BroodsClient();
const result = await client.run(api.agents.myAgent, {
input: "Hello, who are you?",
});

console.log(result.text);
// You are a helpful assistant...

Curl equivalent:

curl -X POST "https://gateway.broods.app" \
-H "Authorization: Bearer $BROODS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentId": "agent_...",
"eventId": "req-001",
"conversationKey": "my-conversation",
"events": [
{ "role": "user", "content": [{ "type": "text", "text": "Hello, who are you?" }] }
]
}'

Streaming Run (yield parts as they arrive)

for await (const part of client.stream(api.agents.myAgent, {
input: "Tell me a story.",
})) {
if (part.type === "text-delta") {
process.stdout.write(part.text);
}
if (part.type === "tool-call") {
console.log("\n[tool]", part.toolName, part.input);
}
if (part.type === "reasoning") {
console.log("\n[thinking]", part.text);
}
}

Curl equivalent:

curl -X POST "https://gateway.broods.app" \
-H "Authorization: Bearer $BROODS_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"agentId": "agent_...",
"eventId": "req-002",
"conversationKey": "my-conversation",
"events": [
{ "role": "user", "content": [{ "type": "text", "text": "Tell me a story." }] }
]
}'

The SSE stream emits Vercel AI SDK TextStreamPart events: text-delta, tool-call, tool-result, finish, error, etc.

Async Run (long-running tasks)

const job = await client.runAsync(api.agents.myAgent, {
input: "Generate a detailed report.",
});

console.log("Polling:", job.statusUrl);

const status = await job.wait({ intervalMs: 2000, timeoutMs: 300_000 });

if (status.status === "completed") {
console.log(status.response);
} else if (status.status === "failed") {
console.error(status.error);
} else if (status.status === "awaiting_approval") {
console.log("Approval needed:", status.approvals);
}

Curl equivalent:

# Start async job
curl -X POST "https://gateway.broods.app/async" \
-H "Authorization: Bearer $BROODS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentId": "agent_...",
"eventId": "req-003",
"conversationKey": "my-conversation",
"events": [
{ "role": "user", "content": [{ "type": "text", "text": "Generate a detailed report." }] }
]
}'

# Poll status
curl "https://gateway.broods.app/status/req-003?agentId=agent_..." \
-H "Authorization: Bearer $BROODS_API_KEY"

Full-Fidelity Events

For multimodal input, tool responses, or ephemeral system instructions, use the events array instead of the input shorthand:

const result = await client.run(api.agents.myAgent, {
events: [
{ role: "system", content: "Answer concisely.", persist: false },
{
role: "user",
content: [
{ type: "text", text: "What's in this image?" },
{ type: "image", image: "data:image/png;base64,iVBORw0KGgo..." },
],
},
],
});

Per-Run Overrides

Override model settings for a single invocation without touching the deployed config:

const result = await client.run(api.agents.myAgent, {
input: "Summarize today's plan.",
model: {
temperature: 0.3,
maxOutputTokens: 4096,
providerOptions: {
openai: { reasoningEffort: "high" },
},
},
});

Reserved keys (provider, modelId, output, apiKey) are rejected so a request cannot swap the model or credentials.

Cron Jobs at Runtime

Create, list, update, and delete cron jobs programmatically:

// Create a cron job
const cron = await client.createCron({
name: "Daily digest",
agent: api.agents.myAgent,
input: "Summarize today's activity.",
scheduleExpression: "cron(0 9 * * ? *)",
timezone: "Europe/Amsterdam",
});

// List all crons
const crons = await client.listCrons();

// Get a specific cron
const job = await client.getCron(cron.cronId);

// List recent runs
const runs = await client.listCronRuns(cron.cronId, { limit: 10 });

// Update
await client.updateCron(cron.cronId, { status: "paused" });

// Delete
await client.deleteCron(cron.cronId);

Python (Coming Soon)

A Python SDK is on the roadmap. Until then, use the HTTP endpoints directly:

import requests

response = requests.post(
"https://gateway.broods.app",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json={
"agentId": "agent_...",
"eventId": "req-001",
"conversationKey": "my-conversation",
"events": [
{"role": "user", "content": [{"type": "text", "text": "Hello"}]}
],
},
stream=True,
)

for line in response.iter_lines():
if line.startswith(b"data: "):
part = json.loads(line[6:])
print(part)

WebSocket (Real-time Streaming)

For browser or persistent-connection clients, use the WebSocket gateway instead of SSE:

import { WebSocketClient } from "broods";
import { api } from "./broods/_generated/api";

const wsClient = new WebSocketClient({
baseUrl: "https://gateway.broods.app",
apiKey: "fp_env_...",
});

const subscription = wsClient.subscribe({
agent: api.agents.myAgent,
events: [
{ role: "user", content: [{ type: "text", text: "Hello!" }] },
],
}, {
onMessage(message) {
if (message.type === "text-delta") {
process.stdout.write(message.text);
}
},
onDone() {
console.log("\n[done]");
},
onError(error) {
console.error("[error]", error.message);
},
});

// Close the connection when finished
// subscription.close();

Or use the async-generator form:

for await (const message of wsClient.stream({
agent: api.agents.myAgent,
events: [
{ role: "user", content: [{ type: "text", text: "Hello!" }] },
],
})) {
if (message.type === "text-delta") {
process.stdout.write(message.text);
}
}

See Architecture for the WebSocket protocol details.

CLI Runtime Commands

The CLI includes runtime helpers that do not require writing code:

# Run an agent once and pretty-print the result
broods run my-agent "What is the capital of France?"

# Stream live logs for the whole project
broods stream

# Backfill recent logs then live-tail
broods logs --limit 100

# List deployed agents
broods agent list

# Show one agent's resolved config
broods agent get my-agent