Skip to main content

Command Palette

Search for a command to run...

BDK

Deploy a BDK project

Deploying a Bot Development Kit (BDK) project from a pushed Git ref creates a stable service. Cursor-managed hosting builds the selected ref and operates the runtime; self-hosting gives you control of the network, process, and filesystem.

Choose managed hosting or self-hosting

OptionUse it whenYou manage
Cursor-managed hostingYou want the shortest path from Git to a running agentSource, declared egress, secrets, and agent behavior
Self-hostingYou need your own network, proxy, filesystem, or process controlsThe Node process, TLS, auth, secrets, state, monitoring, and upgrades

The rest of this guide starts with managed hosting. The self-host recipe uses the same project and HTTP API.

Deploy from Git

Commit and push the exact ref you want to run, then sign in, validate, and deploy. The preferred CLI is bdk.

cd my-agentbdk loginbdk whoamibdk validatebdk deploy

The deploy command waits until the runtime is running and prints the stable deployment URL.

deploy reads from Git; it does not upload your working tree. Inside a checkout, it infers the HTTPS origin, current ref, agent path, and slug. Pass them explicitly when the checkout is not the source you want:

bdk deploy \  --repo https://github.com/acme/agents \  --ref main \  --path agents/weather \  --slug weather-agent

The source repository must be available through the team's repository integration, and a nested --path must contain an installable BDK project.

Connect deployed peers

A team-owned deployment can call another agent deployed by the same team with defineConnection({ agent: "weather-agent" }). Deploy the specialist and the caller; Cursor-managed hosting resolves the slug and authenticates the call, so you don't configure a peer URL, header, or secret.

Redeploy the caller after adding or changing a peer connection. An agent last deployed before hosted peer connections became available also needs one redeploy. See Peer agents for delegation, session affinity, and local development.

Privacy Mode

A hosted deployment stores a snapshot of its source repository, along with the sessions, KV, files, and logs the agent creates for your team. Whether managed hosting is available depends on the privacy setting that applies to you, which is your team's setting when the team enforces one:

Privacy settingManaged hosting
Privacy ModeAvailable. Cursor stores deployment data the same way it does without Privacy Mode, and the agent's model requests get the same Privacy Mode handling as your other Cursor requests.
Privacy Mode (Legacy)Not available. deploy, a hosted session, and an eval run all refuse.

deploy refuses because a deployment stores a snapshot of your repository. A hosted session refuses, and Cursor does not store the message. An eval run refuses because it stores prompts and replies. Switch to Privacy Mode, or ask a team admin when your team enforces this setting.

The stored data includes the memory journal, which bdk init turns on. The journal holds user messages and the agent's replies. With Privacy Mode, Cursor stores it only to run your agent and doesn't train on it.

Add egress and secrets

Declare the external hosts and secret names the agent needs. Mounted extensions add the ones they declare, so list only what your own code calls; bdk info --dir . shows the combined list and what each mount adds. After the deployment exists, set each value at the hidden prompt and follow the CLI or dashboard instruction to redeploy.

// bot/agent.tsimport { defineAgent } from "@cursor/bdk";export default defineAgent({  hosting: {    egressDomains: ["api.weather.example.com"],    secretNames: ["WEATHER_API_KEY"],  },});
bdk secrets set weather-agent WEATHER_API_KEYbdk secrets list weather-agentbdk deploy --dir . --slug weather-agent

Commit secret names, never values. secrets set accepts names and reads values without echoing them; secrets list returns names and creation times only. Do not pass NAME=VALUE, print a secret to verify it, or put names beginning with reserved CURSOR_ in secretNames.

A hosted deployment receives its secrets per request, after its modules are loaded, so code that reads process.env while a module is still loading sees nothing. Read a secret inside the handler, tool, or callback that needs it, and give an MCP connection its credential as a ${NAME} template, which resolves when the connection opens. See credentials in headers and env. SCM webhook channels go one step further and name their secrets in the channel definition, as { secretName: "GITHUB_WEBHOOK_SECRET" }, so the platform can verify each delivery's signature before any compute starts. validate rejects a literal or getter there. The GitHub guide shows the named form.

Enter egress hosts without schemes or paths. An HTTPS host needs no port; add one, as clickhouse.example.com:9440, only for a protocol the proxy reads no hostname from. The Host MCP OAuth guide covers OAuth-backed MCP servers on a hosted agent.

Use the hosted agent

Verify a hosted turn

After deploy reports running, message the deployment from the CLI:

bdk run --prod --slug weather-agent \  --message "Forecast for Paris"

The command returns as soon as the deployment accepts the turn, so its output has a deliveryId and workflowId but no sessionId yet; the session is created when the turn starts. Add --dry-run to check a deployment without side effects: read tools run and write tools are stubbed.

Find the new session in the deployment's recent output, which prints a ==> ses_... (http) <== header for each session, or open the deployment from Deployed Agents in the dashboard and select Sessions:

bdk logs --prod --once --slug weather-agent

Then follow the turn:

bdk session ses_... --prod --slug weather-agent

The command lists each hosted run with its status and log lines. While the turn is still working, it reports how many events have arrived and prints Turn running; runs may lag behind events. Rerun it until the latest run shows a final status such as finished. A high-effort turn can take several minutes, and its run can show no logs until it ends, so a growing event count is the progress signal.

To continue the same conversation, pass --session ses_... to run --prod. bdk playground --prod --slug weather-agent --session ses_... opens the session in the dashboard playground. Hosted deployments don't support bdk chat, call, sessions, cost, or mcp; use run --prod, logs --prod, and session --prod instead.

Send work to the deployment

A hosted agent wakes from its channels: Slack mentions and DMs, SCM events, and custom channel routes. External HTTP clients call a custom route on the stable alias URL and send the alias token on every request:

curl -X POST "$AGENT_ALIAS_URL/v1/channels/tickets/ticket" \  -H "X-Agent-Alias-Token: $AGENT_ALIAS_TOKEN" \  -H 'content-type: application/json' \  -d '{"ticketId":"ENG-142","message":"CSV export returns 500"}'

The deployment answers 202 Accepted with an empty body as soon as the request arrives, then runs the route's handler, so the caller never receives a session ID or a result. Deliver results from the channel, as described in Route responses.

To confirm the work started, find the new session with bdk logs --prod and follow it with bdk session --prod, as in Verify a hosted turn.

Protect the alias token

The first deploy prints the alias token once. Store it outside terminal transcripts; it cannot be retrieved later. If it is lost or exposed, bdk rotate-token weather-agent replaces it and invalidates the old value.

deployment --json can include short-lived access headers, so treat that output as a credential too.

For a custom webhook whose provider cannot send the alias token, use publicEndpoint() only when the channel verifies the provider signature. That opens the custom channel path, not the built-in session or tool APIs. See Webhooks.

Update the deployment

Push the new ref and deploy the same slug. The stable URL remains while the new generation replaces the previous one.

bdk deploy --dir . --slug weather-agent

A redeploy replaces its source, its watched repositories, and any egress domains supplied through CLI flags. Pass every --cursor-events-repo value again; without the flag, the deployment watches its GitHub source repository. Keep source-controlled egress in the hosting block when possible.

Use bdk deployment weather-agent to inspect a rollout. The CLI reference owns --no-wait, multi-agent deployment, stop, and delete behavior.

Keep state across replacements

Managed hosting persists framework-owned session, KV, and file state across normal runtime replacements. Files written elsewhere on the runtime's local filesystem are disposable; use ctx.host.kv or ctx.host.files for durable application state.

On architecture v2, the default, reminders take a prompt or a named handler. See Reminders.

Self-host securely

Run BDK under Node 22.13 or newer, never Bun. One supervised process can serve every agent under a directory while a persistent state root keeps sessions across restarts.

export CURSOR_API_KEY="<cursor-api-key>"export BDK_BEARER_TOKEN="$(openssl rand -hex 32)"bdk serve \  --dir /srv/agents \  --host 127.0.0.1 \  --port 3000 \  --state-root /var/lib/bdk \  --bearer-token "$BDK_BEARER_TOKEN"

Before exposing the host:

  • Put TLS or an authenticating proxy in front of the loopback server.

  • Keep --bearer-token on shared hosts. Use --allow-anonymous only behind a proxy that authenticates every caller.

  • Mount --state-root on a persistent volume outside the agent repository and back it up.

  • Inject credentials at startup instead of baking them into an image.

  • Run the process under a supervisor and enable schedules on exactly one serving process per project.

Containers use the same command with --host 0.0.0.0, a mounted state volume, and an authenticating network boundary. The Channels reference covers per-caller and channel-specific auth.

Observability

Use bdk logs --prod and bdk session <sessionId> --prod for a hosted session's runs and logs, OpenTelemetry for traces and metrics, and session traces for a local conversation.

  • Early-alpha migration: move a hosted architecture v1 project to v2 through a reviewed pull request
  • CLI reference: inspect, update, stop, delete, and rotate deployments
  • GitHub: Cursor-event repositories and direct webhook delivery
  • Slack: provision a dedicated hosted Slack app
  • Host MCP OAuth: reach OAuth-backed MCP servers from a hosted agent
  • Troubleshooting: diagnose failed or stale deployments