Resource Configuration
Broods uses a code-first configuration model. You define agents, workspaces, sandboxes, skills, tools, cron jobs, and channels as typed TypeScript resources inside a broods/ folder. The CLI compiles these into a manifest, syncs them to the cloud, and generates typed runtime references.
Project Layout
my-project/
broods/
index.ts # Resource definitions
_generated/ # Auto-generated by broods dev/deploy
api.ts # Typed agent/resource references
ids.ts # Deployed IDs
greeting-skill/ # Skill bundle (optional)
SKILL.md
tools/ # Custom tool sources (optional)
my-tool.ts
.env.local # Local secrets (never commit)
env — Deferred Secrets
Never bake secrets into your resource files. Use env.NAME to create a deferred reference that resolves on the server at runtime:
import { defineAgent, env } from "broods";
export const myAgent = defineAgent({
name: "my-agent",
config: {
provider: {
openai: { apiKey: env.OPENAI_API_KEY },
},
},
});
Both forms are equivalent:
env.OPENAI_API_KEY // property access
env("OPENAI_API_KEY") // call form
Set the value with the CLI:
broods env set OPENAI_API_KEY
Or let broods dev auto-push it from your local .env.local.
envis notprocess.env. Usingprocess.env.OPENAI_API_KEYwould bake your local value into the deployed config. Always useenv.NAMEfor anything that should stay server-side.
Agents
defineAgent is the core resource. It holds model, provider, tools, channels, workspaces, skills, subagents, and hooks.
import { defineAgent, defineSandbox, defineWorkspace, env } from "broods";
export const myAgent = defineAgent({
name: "my-agent",
description: "A general-purpose assistant", // visible to parent agents
config: {
provider: {
google: { apiKey: env.GOOGLE_API_KEY },
},
model: {
provider: "google",
modelId: "gemini-3-flash",
temperature: 0.7,
},
agent: {
system: "You are a helpful assistant.",
maxTurn: 10,
},
publicAccess: true, // enable public SSE/WebSocket endpoint
},
});
Supported Providers
| Provider | Config key | Required fields |
|---|---|---|
google | apiKey | |
| OpenAI | openai | apiKey |
| Bedrock | bedrock | region, apiKey |
| Gateway | gateway | apiKey |
| MiniMax | minimax | apiKey |
Reasoning / Thinking Tokens
Use standard Vercel AI SDK providerOptions in config.model:
model: {
provider: "openai",
modelId: "o3",
providerOptions: {
openai: {
reasoningEffort: "high",
reasoningSummary: "auto",
},
},
},
| Provider | Thinking config |
|---|---|
| OpenAI | providerOptions.openai.reasoningEffort |
| Anthropic | providerOptions.anthropic.thinking |
providerOptions.google.thinkingConfig | |
| MiniMax | providerOptions.anthropic.thinking (Anthropic-compatible) |
Structured Output
model: {
provider: "google",
modelId: "gemini-3-flash",
output: {
type: "object",
name: "analysis",
description: "Structured analysis result",
schema: {
type: "object",
properties: {
summary: { type: "string" },
confidence: { type: "number" },
},
required: ["summary", "confidence"],
},
},
},
Tools
Enable built-in and custom tools:
config: {
tools: {
tavilySearch: {
enabled: true,
apiKey: env.TAVILY_API_KEY,
searchDepth: "advanced",
},
googleSearch: { enabled: true },
handoffs: { enabled: true },
},
},
See External Tools for uploading custom tools.
Channels
Attach one or more channels to an agent:
import { defineTelegramChannel } from "broods";
export const telegram = defineTelegramChannel({
botToken: env.TELEGRAM_BOT_TOKEN,
webhookSecret: env.TELEGRAM_WEBHOOK_SECRET,
allowedChatIds: [123456789],
streaming: { mode: "progress" },
});
export const myAgent = defineAgent({
name: "my-agent",
config: {
channels: [telegram],
},
});
Each channel type has its own constructor. See Channels.
Workspaces
Reference workspace resources or pass per-workspace sandbox overrides:
import { defineWorkspace } from "broods";
export const notes = defineWorkspace({
name: "notes",
config: {
storage: { provider: "s3" },
harness: { enabled: true },
},
});
export const myAgent = defineAgent({
name: "my-agent",
config: {
sandbox: mySandbox,
workspaces: [
notes, // inherit agent sandbox
{ workspace: notes, sandbox: null }, // read-only
{ workspace: teamWorkspace, sandbox: k8sSandbox }, // per-workspace override
],
},
});
Subagents
export const research = defineAgent({
name: "research",
config: { /* ... */ },
});
export const myAgent = defineAgent({
name: "my-agent",
config: {
subagent: {
enabled: true,
allowed: [research],
context: "inherited",
mode: "persistent",
},
},
});
See Sub Agents for full details.
Skills
import { defineSkill } from "broods";
export const supportFlow = defineSkill({
name: "support-flow",
config: { path: "support-flow" },
});
export const myAgent = defineAgent({
name: "my-agent",
config: {
skills: {
enabled: true,
allowed: [supportFlow],
},
},
});
See Skills for bundle format.
Hooks
Configure lifecycle webhooks:
config: {
hooks: {
webhooks: [
{
enabled: true,
url: "https://example.com/webhooks",
secret: env.WEBHOOK_SECRET,
events: ["agent.started", "agent.finished", "agent.failed"],
},
],
},
},
See Lifecycle Webhooks.
Session
Control history pruning and compaction:
config: {
session: {
pruning: { enabled: true },
compaction: {
enabled: true,
maxContextLength: 100_000,
},
},
},
Sandboxes
import { defineSandbox, env } from "broods";
export const lambdaSandbox = defineSandbox({
name: "lambda-sandbox",
config: {
provider: "lambda",
network: { mode: "deny-all" },
permissionMode: "ask",
timeout: 60,
},
});
export const k8sSandbox = defineSandbox({
name: "persistent-k8s",
config: {
provider: "kubernetes",
network: { mode: "allow-all" },
permissionMode: "bypass",
persistent: true,
lifecycle: { idleTimeoutSeconds: 1800 },
options: { mountAwsS3Buckets: true },
},
});
Supported providers: lambda, e2b, daytona, kubernetes, vercel.
See Workspace & Sandbox for the full sandbox model.
Workspaces
import { defineWorkspace } from "broods";
export const notes = defineWorkspace({
name: "notes",
config: {
storage: { provider: "s3" },
harness: { enabled: true },
},
});
Skills
import { defineSkill } from "broods";
export const supportFlow = defineSkill({
name: "support-flow",
config: { path: "support-flow" },
});
The path is relative to broods/ and must contain a SKILL.md file.
Tools
import { defineTool } from "broods";
export const analyze = defineTool({
name: "analyze",
config: {
path: "tools/analyze.ts",
description: "Analyze structured data.",
inputSchema: {
type: "object",
properties: {
data: { type: "array" },
},
required: ["data"],
},
defaultConfig: {},
},
});
The CLI bundles the TypeScript entrypoint into a self-contained ESM module and uploads it. See External Tools for the bundle contract.
Cron Jobs
import { defineCron } from "broods";
export const dailyDigest = defineCron({
name: "daily-digest",
config: {
agent: myAgent,
input: "Summarize today's activity.",
scheduleExpression: "cron(0 9 * * ? *)",
timezone: "Europe/Amsterdam",
},
});
Or use events instead of input for multimodal payloads:
config: {
agent: myAgent,
events: [
{ role: "user", content: [{ type: "text", text: "Check status." }] },
],
scheduleExpression: "rate(1 hour)",
}
Channels
Each channel has a dedicated constructor:
import {
defineTelegramChannel,
defineDiscordChannel,
defineSlackChannel,
defineGitHubChannel,
definePancakeChannel,
defineZaloChannel,
} from "broods";
A channel definition must be attached to exactly one agent. An agent may have multiple channels, but not multiple of the same type.
Project Config
Optionally export a defineBroods config to set project defaults:
import { defineBroods } from "broods";
export default defineBroods({
project: "my-project",
environments: {
dev: "development",
deploy: "production",
},
dashboardUrl: "https://dashboard.broods.app",
});
These values can be overridden by CLI flags (--project, --env) or .env.local.
Validation
The CLI validates resource configs at compile time:
- Unknown agent config keys are rejected with suggestions (e.g.
workspace:→ did you meanworkspaces:?). - Duplicate resources are rejected.
- Skill bundles must contain
SKILL.md. - Tool bundles must build successfully as ESM.
- Workspace storage provider must be
s3. - Sandbox mounts must support S3 workspace access.
These checks run during broods dev and broods deploy, so you get fast feedback without deploying broken config.
Generated References
After broods dev or broods deploy, the CLI writes _generated/api.ts with typed references:
import { api } from "./broods/_generated/api";
// api.agents.myAgent → AgentReference
// api.channels.myTelegram → ChannelReference
// api.workspaces.notes → string (workspaceId)
// api.sandboxes.lambda → string (sandboxId)
Use these references with BroodsClient for fully typed runtime calls:
import { BroodsClient } from "broods";
import { api } from "./broods/_generated/api";
const client = new BroodsClient();
await client.run(api.agents.myAgent, { input: "Hello!" });
Raw API Fallback
The code-first layer compiles to the same manifest the raw account API accepts. If you ever need to call the REST API directly, the shapes are identical. See the API Reference for the full OpenAPI spec.