Skip to main content

Command Palette

Search for a command to run...

BDK

BDK CLI

The Bot Development Kit (BDK) is published as @cursor/bdk with the bdk CLI.

bdk <command>

The command catalog below documents the bdk binary from @cursor/bdk. Run it with Node 22.13 or newer; Bun is not supported. Commands exit nonzero when validation or a synchronous request fails; asynchronous commands can exit 0 once work is accepted. Project paths use the BDK project layout.

Install @cursor/bdk to obtain the binary. bdk help prints top-level help; the Slack, GitHub, GitLab, and Bitbucket command packs provide their own help subcommands.

Command catalog

Development commands

CommandContract
help, --help, -hPrint top-level help
serveServe one or more agents over HTTP
devServe agents with local-development behavior
docsServe the documentation bundled with @cursor/bdk
initScaffold a BDK project
convert-automationExport a Cursor Automation into a project
migrateMove an early-alpha project to architecture v2 through a pull request
install-skillsRefresh the bundled coding-agent skills
infoPrint the discovered project surface
validateCheck project diagnostics and set the exit status
manifestPrint deployment metadata as JSON
versionPrint the installed package version
updateUpgrade the installed CLI
loginSign the host in to Cursor
logoutRemove the stored Cursor credential
whoamiShow the active Cursor credential

Session and eval commands

CommandContract
chatTalk to a running agent
resumeReattach chat to a previous session
runStart or continue work on a local, running, or hosted agent
callCall a server tool without a model turn
skillRead an authored skill without a model turn
logsFollow or dump agent logs
sessionsList sessions
sessionInspect a session or start a hosted session turn
costReport token usage and estimated cost
playgroundOpen an agent's playground
trajectorySummarize a saved event stream
evalList, run, inspect, or cancel evals

Managed hosting commands

CommandContract
deployDeploy one or more agents
deploymentsList deployments
deploymentInspect one deployment
stopStop a deployment
startStart a stopped deployment
killStop a deployment, cancel its runs, and lock deploys
unlock-deploysLet a killed deployment deploy again
cancel-runsCancel active runs and reminder wakes
event-reposReplace a deployment's event repositories
upgradeMove a deployment to a release
rollbackMove a deployment to an earlier release
deleteDelete a deployment
rotate-tokenReplace a deployment's alias token
secretsSet, list, or remove deployment secrets
imagesPush, list, or remove container images for persistent agents

Connection and channel commands

CommandContract
mcpProxy an agent's MCP endpoint over stdio
mcp installAdd the agent to an MCP client config
mcp oauthAuthorize an MCP connection
slackProvision and check Slack channel apps
githubForward, replay, and inspect GitHub webhooks
gitlabReplay and inspect GitLab webhooks
bitbucketReplay and inspect Bitbucket webhooks

Targets

Commands that send requests support these targets:

TargetSelectionCommands
Ephemeral local serverOmit --url and --prodrun, call, skill, eval
Running serverPass --url <baseUrl>chat, resume, run, call, skill, eval, logs, sessions, session, cost, playground, mcp
Default local serverOmit --url and --prod; uses http://127.0.0.1:3000chat, resume, logs, sessions, session, cost, playground
Hosted deploymentPass --prodrun, session, logs, playground

An explicit --url must include the slug for a multi-agent server, such as http://127.0.0.1:3000/pr-approver. --slug never changes an explicit URL. --url and --prod are mutually exclusive.

OptionContract
--dir <path>Select the project root. The default is the current directory.
--url <baseUrl>Use a running agent instead of local project discovery.
--prodUse the hosted deployment. Only run, session, logs, and playground accept it; chat, resume, call, skill, sessions, cost, and mcp report that the deployment doesn't support the command, and eval rejects the flag.
--slug <slug>Select an agent from a multi-agent project or a hosted deployment. Under --prod, the default is the --dir basename.
--team <id>Select a Cursor team. The signed-in account's team is the default.
--api-key <key>Override the Cursor credential for commands that authenticate with Cursor.
--bearer-token <token>Authenticate to a running server with a bearer token.
--state-root <path>Select local state for serve and ephemeral run, call, skill, and eval targets. Running and --prod targets ignore it.
--jsonRequest machine-readable output when the command supports it. run already defaults to JSON.

Local servers

Serve agents

serve mounts every project discovered under --dir:

bdk serve [--dir <path>] [--port <n>] [--host <host>]  [--mode multi|single] [--dev] [--api-key <key>]  [--state-root <path>]  [--bearer-token <secret> | --allow-anonymous]  [--allow-anonymous-cursor-github]  [--allow-anonymous-cursor-account-mcp]  [--allow-anonymous-grokbot]  [--public-url <url>]  [--peers-url <url>]  [--no-schedules] [--no-playground] [--no-docs]  [--cursor-events --repo <owner/name>]...
OptionContract
--port <n>Listen on this port. The default is 3000; 0 selects an available port. When an omitted default is occupied, the CLI selects the next port. An occupied explicit port fails with a next-port hint.
--host <host>Bind this host. The default is loopback-only 127.0.0.1.
--mode multiMount projects at /<slug>/v1/* and /<slug>/playground, with an index at /. This is the default.
--mode singleMount one project at /v1/* and /playground. Declared peers are omitted with a warning unless --peers-url is set.
--devDisable automatic schedule and reminder firing, admit unsigned loopback GitHub deliveries, and enable local playground access.
--state-root <path>Store local sessions, streams, workspaces, and channel state here. Keep durable state outside a repository whose rules shouldn't reach agent workspaces.
--bearer-token <secret>Require this token on routes without authored authentication. Mutually exclusive with --allow-anonymous.
--allow-anonymousAdmit callers as one anonymous principal. Use it only behind a trusted network boundary.
--allow-anonymous-cursor-githubLet anonymous callers use sessions with a Cursor account's repository-scoped GitHub credential. Requires an authenticating proxy.
--allow-anonymous-cursor-account-mcpLet anonymous callers use Cursor account MCP connections. Requires an authenticating proxy.
--allow-anonymous-grokbotLet anonymous callers drive hosted Grok Bot runtime agents. Requires an authenticating proxy.
--public-url <url>Set the externally reachable base URL that turns running off the serve host use for peer MCP and host bridges. It does not expose the server; configure the listener or proxy separately. Local-runtime peers use loopback.
--peers-url <url>Resolve declared peers for a single-agent serve through a hosting-provided peer service. Cursor-managed hosting sets this option automatically; a multi-agent serve rejects it.
--no-schedulesDisable schedule firing outside dev mode.
--no-playgroundSkip the playground.
--no-docsSkip the documentation site at /docs.
--cursor-eventsReceive SCM events through Cursor. Requires sign-in and one or more repeatable --repo owner/name values.

Multi-agent slugs start with a letter or digit and contain only letters, digits, _, or -. The reserved slugs are v1, playground, and docs.

Develop locally

dev is serve --dev with an optional positional project path:

bdk devbdk dev ./bdk-pr-reviewer --port 3000

It accepts every serve option. Pass at most one positional path, and don't combine it with a different --dir.

Serve the docs

bdk docs [--port <n>] [--host 127.0.0.1] [--print]

docs serves the bundled documentation without an agent project. It uses an available loopback port by default and stays open until Ctrl-C. --print prints the URL without opening a browser.

Sessions and turns

Chat with an agent

chat connects to a running server and never starts an ephemeral one:

bdk chat [--url <baseUrl>] [--message <text>]  [--session <id> | --resume] [--continuation-token <token>]  [--slug <slug>] [--json] [--text] [--no-color]
Input modeBehavior
TTY without --messageOpen an interactive REPL.
TTY with --messageSend the message, then keep the REPL open.
Non-TTY with --messageSend one turn and exit.
Non-TTY without --messageRead newline-delimited messages until EOF.
--json --message <text>Send one turn and print { ok, sessionId, continuationToken, trajectory }.
--json --text --message <text>Print a compact trajectory instead of JSON.

Use --session <id> to reattach a stored session. If you omit --continuation-token, the CLI looks it up from the target's session list. --resume selects the most recently updated session with a continuation token. An explicit session ID takes precedence.

Resume a session

resume provides the same reattachment contract as chat --session:

bdk resume [sessionId] [--url <baseUrl>]  [--message <text>] [--json] [--text]  [--continuation-token <token>] [--slug <slug>]

Omit the session ID to select the most recently updated followable session. The command replays the transcript before accepting follow-ups. resume --json requires --message.

Run turns

run sends messages to an ephemeral, running, or --prod target:

bdk run [--dir <path>] [--message <text>]...  [--messages-file <path>] [--url <baseUrl> | --prod]  [--session <id>] [--continuation-token <token>]  [--events <file> | --no-events] [--text]  [--timeout-ms <n>] [--no-stream] [--slug <slug>] [--team <id>]  [--dry-run] [--as-of <instant>] [--component <key>]
OptionContract
--message <text>Send a user message. Repeat it for a multi-turn local or --url run. A --prod run takes exactly one message.
--messages-file <path>Read a JSON array of strings. File messages run before repeated --message values.
--session <id>Continue a session. With --prod, pass a hosted ses_... ID from a session that run --prod or session --prod started; Slack, SCM, and custom-route sessions can't be continued this way.
--continuation-token <token>Continue the session selected by --session on a running server. --prod doesn't accept it.
--events <file>Write the raw NDJSON stream to this path.
--no-eventsSkip the NDJSON trace.
--textPrint a compact trajectory instead of JSON.
--timeout-ms <n>Stop waiting after a positive number of milliseconds. There is no default timeout.
--no-streamHide live tool and reply progress on stderr.
--dry-runStart a --prod session that runs read tools and stubs write tools.
--as-of <instant>Freeze a --prod session's clock at an ISO-8601 instant with a timezone, such as 2026-08-31T12:00:00Z.
--component <key>Wake a named component of a --prod deployment instead of its default. A continued session must belong to that component.

For local and running-server targets, JSON output contains ok, sessionId, continuationToken, trace, playgroundUrl, playgroundHint, visualize, and trajectory. The trace value gives the saved path when event output is enabled.

With --prod, run returns as soon as the deployment accepts the turn and exits 0 before the turn outcome is known. It prints deliveryId, workflowId, and sessionMode, plus dryRun and asOf when set. A fresh start has no sessionId yet; a continuation echoes the --session value. --events, --no-events, --text, --timeout-ms, and --no-stream have no effect. See Verify a hosted turn for finding and following the new session.

Call a tool

call invokes a server tool without a model turn:

bdk call <tool> [--input <json>]  [--dir <path> | --url <baseUrl>]  [--session <id>] [--slug <slug>]

--input accepts JSON and defaults to {}. --session uses the session workspace and records the call on its event stream. The command prints the server's JSON response and succeeds only when the HTTP response succeeds with ok: true.

Hosted deployments don't support call. Start a model turn with run --prod and check it with session.

See Tools for validation, busy-session behavior, and error codes.

Read a skill

skill reads an authored skill without a model turn:

bdk skill <name> [--dir <path> | --url <baseUrl>]  [--slug <slug>] [--text]

The default output is the server's JSON response. --text prints the rendered SKILL.md content.

List sessions

bdk sessions [--url <baseUrl>]  [--slug <slug>] [--bearer-token <token>] [--json]

Text output shows the session ID, channel, mode, turn count, running status, and update time. --json prints { sessions }, including continuation tokens.

Hosted deployments don't support sessions. Find a hosted session ID in the logs --prod headers or the deployment's Sessions list in the dashboard, then check it with session <sessionId> --prod.

Inspect a session

bdk session <sessionId> [--url <baseUrl> | --prod]  [--slug <slug>] [--team <id>]  [--json | --text | --events] [--out <file.ndjson>]bdk session --prod [<sessionId>] --slug <slug> --message <text>  [--team <id>] [--dry-run] [--as-of <instant>] [--component <key>]
OptionContract
No output optionPrint a compact trajectory.
--textSelect the compact trajectory explicitly.
--jsonPrint the trajectory object.
--eventsPrint { sessionId, events } with the raw event list.
--out <file.ndjson>Write the raw NDJSON trace instead of printing it.
--prod --message <text>Start a hosted session, or continue the supplied hosted session ID, with the same contract as run --prod.

--events and --json are mutually exclusive. Use resume to continue a conversational session on a local or running server.

With --prod, the command prints the session's hosted executions: one line per run with its status, duration, and time, followed by that run's log lines. --json prints { sessionId, executions, startLog, ... }. --events and --out aren't available. While a turn is running, text output also reports the event count and latest event type and prints Turn running; runs may lag behind events. A run can show running with no logs until the turn ends, so a growing event count is the progress signal.

Follow logs

bdk logs [sessionId] [--url <baseUrl> | --prod]  [--session <sessionId>] [--slug <slug>] [--team <id>] [--once] [--json]

The command follows logs until Ctrl-C. --once prints the current buffer and exits; --json emits newline-delimited JSON events. With --prod, it follows the output of the hosted deployment's most recent sessions on every channel and prints a ==> <sessionId> (<channel>) <== header each time the output switches sessions. Pass a session ID, as an argument or with --session, to follow only that session; a session ID requires --prod. Hosted log events carry sessionId and line rather than index and at.

Report costs

bdk cost [sessionId] [--url <baseUrl>]  [--slug <slug>] [--json]

With a session ID, cost prints per-turn token usage and estimated cost. Without one, it prints one row per session and a total. Turns saved before cost tracking appear as unpriced. --json prints the underlying report or { sessions } for an aggregate.

Open the playground

bdk playground [--url <baseUrl> | --prod] [--session <id>]  [--slug <slug>] [--team <id>] [--bearer-token <token>] [--print]

The command prints the playground URL and opens it unless --print is set. --session opens a deep link. A running target with credentials that a browser can't send starts a loopback proxy and stays open until Ctrl-C. With --prod, the URL opens the deployment's playground under Deployed Agents in the dashboard.

Inspect a trajectory

bdk trajectory --events <file.ndjson> [--text]

The command converts an NDJSON stream into the trajectory JSON returned by run. --text prints the compact view.

Evals

Run evals

eval discovers evals/**/*.eval.{ts,js} and runs selected cases:

bdk eval [--dir <path>] [evalId...]  [--list] [--tag <tag>]... [--json] [--verbose]  [--timeout-ms <n>] [--strict] [--max-concurrency <n>]  [--junit <path>] [--artifacts <dir> | --no-artifacts]  [--skip-report] [--out <file.json>] [--no-stream]  [--url <baseUrl>] [--no-wait] [--slug <slug>]

Select an exact case such as weather/nyc, a file prefix such as weather, several IDs, or no IDs for every case. Repeat --tag for OR matching. Projects must provide evals/evals.config.{ts,js} with maxConcurrency between 1 and 200.

OptionContract
--listList matching cases without running them. --list --json prints an array.
--tag <tag>Select a tag. Repeat the option for OR matching.
--jsonPrint { ok, passed, failed, scored, skipped, strict, results }.
--verboseStream t.log lines and reply snippets.
--no-streamHide live progress on stderr.
--strictTreat a scored case below its soft threshold as a failure.
--max-concurrency <n>Override maxConcurrency from the eval config for an ephemeral local run.
--timeout-ms <n>Override the per-case timeout. A case timeout takes precedence, followed by this option, the config timeout, and the 180-second default.
--junit <path>Write JUnit XML for an ephemeral local run.
--artifacts <dir>Select the artifact directory for an ephemeral local run. The default is a timestamped directory under the project's state directory.
--no-artifactsSkip artifacts for an ephemeral local run.
--skip-reportIgnore reporters from eval files and the eval config during an ephemeral local run.
--out <file.json>Also write the full result JSON.
--no-waitReturn after a running server accepts the batch.

A running server prints its Eval ID when it accepts the batch. Use these commands to inspect or cancel it:

bdk eval status [evalId] --url <baseUrl>bdk eval cancel <evalId> --url <baseUrl>

eval status without an ID lists recent remote runs. eval status --out requires an ID. The status and cancel subcommands require --url.

Projects

Scaffold a project

bdk init [directory] [--template <name>] [--var id=value]... [--json]bdk init [directory] --from-grokbot <recipe.json>  [--answers <file>] [--dry-run] [--json]

Without a directory, init prints the setup guide and changes no files. With a directory, it preserves existing scaffold files, adds missing files, installs dependencies, and tries to put bdk on PATH.

OptionContract
--template <name>Use a bundled template: agentic-owners, agents-md, code-wiki, demo, grokbot-agents, security-help, security-reviewer, thermo-quality-review, thermo-review, triage-jira, or triage-linear. triage selects triage-linear.
--var id=valueAnswer a template question without a prompt. Repeat for multiple answers.
--jsonSkip interactive login and skill prompts, then print { ok, directory, template, created, skipped, installed, installError, cliOnPath, cliLinkError, next }. ok reflects dependency installation.

On a TTY, templates with questions run their interview before writing files. init also offers to refresh the bundled coding-agent skills and starts login when the host has no Cursor credential.

Export a Grok Bot recipe

--from-grokbot reads a Grok Bot recipe and maps its profile, selected skills and routines, memory, channels, and connectors into a BDK project. The target directory defaults to the resolved location answer; a positional directory overrides it. A target previously created with bdk init --template is rejected; export into a fresh directory instead.

OptionContract
--from-grokbot <recipe.json>Read the recipe to export.
--answers <file>Read export decisions from a JSON object. Fields present in the file are not asked again. The published schema is schemas/grokbot-answers.schema.json.
--dry-runPrint the planned files, defaults, exclusions, unmapped behavior, placeholders, secret names, warnings, and setup steps without writing files or installing dependencies.
--jsonNever prompt and print machine-readable output. Combine it with --dry-run for a machine-readable preview.

On a TTY, the command asks for missing decisions and offers recipe-derived defaults. Off a TTY, it never prompts, takes defaults where possible, and lists the fields it defaulted.

--dry-run --json prints { ok, dryRun, directory, preview }. The preview contains version, name, resolved answers, defaulted, ignored, files as { path, from }, excluded, unmapped as { from, reason }, fillIns, secrets as { names, reauth }, warnings, and setupSteps. A write with --json also reports files, installed, and installError. A dependency install failure leaves ok: true, sets installed: false, reports installError, and exits 0. Other errors print { ok: false, error } and exit nonzero.

--answers and --dry-run require --from-grokbot. This export mode does not accept --template or --var.

See Export a Grok Bot for the preview-first workflow, mapping table, and post-export checklist.

Convert an Automation

bdk convert-automation <url-or-uuid> [--dir <path>] [--json]

The input can be a Cursor Automation dashboard URL or its UUID. The output directory defaults to ./<automation-name>. Generated files don't overwrite existing paths, and missing scaffold files are added. The following npm install can update lockfiles and run lifecycle scripts from an existing package.json.

--json prints { ok, directory, files, warnings, setupSteps, installed, installError, mcpConnections }. Conversion warnings and dependency-install failures remain visible in this output without failing a completed file conversion. Invalid input, authentication, export, and file-write failures exit nonzero.

See Convert a Cursor Automation for the generated project and features that need manual review.

Migrate an early-alpha project

bdk migrate [--dir <path>] [--repo <https-url>] [--ref <git-ref>]  [--path <agent-path>] [--no-wait] [--json] [--api-key <key>]

migrate applies only to projects deployed on architecture v1 during the BDK early alpha. It reads a pushed Git ref, starts a Cursor cloud agent with the bundled bdk-migrate-v2 skill, and opens a pull request with the source changes. The command waits for the pull request by default and never deploys the project or changes deployment secrets. When it starts an agent, it prints a checklist for the steps after the first deploy: deploy each agent folder, create the prod Slack app, unset peer URL secrets, and set secrets a new slug still needs.

The command prints Nothing to migrate. and exits 0 only when --dir shows no migration work. That check looks for an @cursor/july dependency, architecture: "v1", bot/storage.ts or agent/storage.ts, runtime: "grokbot", a literal SCM credential, a /v1 continuation selector, an anonymous reminder, and a *_MCP_URL peer connection. When any of those is present, or a project file cannot be read, the command starts the agent. It does not read the hosted deployment.

OptionContract
--dir <path>Select the local BDK project. The default is the current directory.
--repo <https-url>Select the source repository. The CLI infers the current checkout's origin when possible.
--ref <git-ref>Select the pushed ref for the cloud agent. The CLI infers the current branch when possible.
--path <agent-path>Select the project path relative to the repository root. The CLI infers it from --dir when possible.
--no-waitPrint the cloud agent URL and return after the agent starts.
--jsonPrint a report with ok, status, agentId, and the cloud agent url. A completed migration adds prUrl and checklist. A run with nothing to migrate uses status: "current" and message (no agent started) or summary (the agent reported it). A blocked or failed migration adds its explanation.
--api-key <key>Override the Cursor credential.

Credential resolution follows the normal order: --api-key, CURSOR_API_KEY, CURSOR_API_KEY_FILE, CURSOR_SERVICE_ACCOUNT_KEY, then the stored bdk login credential. See Migrate an early-alpha project for detection, pull request review, and deployment cutover.

Install coding-agent skills

bdk install-skills [--print] [--json]

The command replaces the installed BDK skills with the package copy and removes stale bundled skills. --print previews the change. --json prints { ok, dryRun, directory, firstInstall, skills, removed }.

Package installation performs this copy. Run bdk install-skills when you need to refresh it.

Inspect a project

bdk info [--dir <path>] [--json]

Text output lists the model, instructions, tools, skills, extensions, connections, subagents, channels, schedules, hooks, hosting settings, and diagnostics. For one unslugged project, --json prints its project info object. For slugged or multi-agent discovery, it prints { agents }.

Validate a project

bdk validate [--dir <path>]

validate prints every discovered project's diagnostics and exits nonzero when any diagnostic has error severity. Use it instead of info --json when a script needs validation status.

Hosting checks run here too. On architecture v2 (the default), a githubChannel credential or a GitLab or Bitbucket webhookSecret written as a literal or a () => process.env.NAME getter is an error whose message quotes the { secretName: "NAME" } form to use instead. A project that still sets architecture: "v1" gets the same finding as a warning, so run validate before removing the pin to list what the migration must rename.

bdk manifest [--dir <path>] [--json]

manifest validates one project and prints its deployment metadata without a network request. Default output is indented JSON; --json prints one compact line.

Credentials and versions

Manage credentials

bdk login [--api-key <key>] [--key-name <name>]bdk whoami [--json]bdk logout
CommandContract
loginUse a supplied API key, or open browser sign-in and store the resulting dashboard-revocable key in the CLI config directory. --key-name labels a browser-created key.
whoamiShow the active credential and its source. --json returns the same identity as JSON.
logoutRemove the stored credential file. It doesn't revoke the API key; revoke the key in the Cursor dashboard.
bdk version [--json]bdk --versionbdk -V

Text output is the version number. --json prints { name, version }.

Update the CLI

bdk update

update checks npm's latest tag and upgrades a recognized global or project install with its package manager. If it can't identify an installed copy, it prints a manual upgrade command instead.

Published installs check for updates at most once every 24 hours. Set AGENT_SERVE_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER, or CI to disable the automatic warning.

Managed hosting

Deploy agents

bdk deploy [--dir <path>] [--slug <slug> | --all] [--team <id>]  [--repo <https-url>] [--ref <git-ref>] [--path <agent-path>]  [--cursor-events-repo <repo>]...  [--allow-domain <domain>]... [--no-wait] [--json]

Managed hosting requires a team with agent hosting enabled. A team service-account API key with agent access can deploy.

OptionContract
--slug <slug>Select one project and set its deployment slug. Under a folder of several agents, this deploys that one agent.
--allDeploy every child under a folder of several agents. For a folder of v2 agents, print one deploy command for each agent.
--team <id>Select the Cursor team.
--repo <https-url>Set the source repository. The CLI infers it from the current checkout when possible. HTTPS is required.
--ref <git-ref>Set the source Git ref. The CLI infers the current branch when possible.
--path <agent-path>Set the project path relative to the repository root.
--cursor-events-repo <repo>Watch a repository's Cursor events. Write owner/name for GitHub and Origin, gitlab.com/<group>/<project> for GitLab (subgroups allowed), or bitbucket.org/<workspace>/<repo> for Bitbucket. Repeat the flag for each repository; the repositories you pass replace the previous list. Without the flag, the deployment watches its GitHub source repository.
--allow-domain <domain>Add an egress hostname. Repeat for multiple domains; values are combined with hosting.egressDomains.
--no-waitReturn after the deployment request is accepted.
--jsonPrint one object for one target or an array for multiple targets.

Deployment slugs contain lowercase letters, digits, _, or -, start with a letter or digit, and have at most 64 characters. Egress entries are lowercase hostnames with an alphabetic top-level domain; one leading *. wildcard is allowed, or a trailing :port for a protocol that is not HTTPS, with at most 64 entries.

By default, deploy waits until the deployment is running and exits nonzero if it reaches a failed state. A first deployment can return an alias token once. Store it as a secret and send it as X-Agent-Alias-Token when calling the stable alias URL.

List deployments

bdk deployments [--team <id>] [--json]

Text output shows slug, status, generation, kind, and update time. --json prints { deployments }. An empty list succeeds.

Inspect a deployment

bdk deployment <slug> [--team <id>] [--json]

Text output includes status, source, routes, secret names, egress domains, and the latest error. --json can include short-lived access headers, so handle its output as a credential.

Stop a deployment

bdk stop <slug> [--team <id>] [--no-wait] [--cancel-runs] [--json]

The command waits for stopped by default. --no-wait returns after the request is accepted. --cancel-runs also requests cancellation of active runs and reminder wakes.

Start a deployment

bdk start <slug> [--team <id>] [--json]

start resumes a stopped deployment. It doesn't remove the deploy lock that kill sets.

Kill a deployment

bdk kill <slug> [--team <id>] [--json]

Use kill in an emergency. It locks deploys of the slug, stops the deployment, and requests cancellation of its active runs and reminder wakes. To bring the deployment back, run unlock-deploys and then start.

Unlock deploys

bdk unlock-deploys <slug> [--team <id>] [--json]

unlock-deploys removes the lock that kill sets, so deploy, upgrade, and rollback work for the slug again. It doesn't resume traffic; run start for that.

Cancel active runs

bdk cancel-runs <slug> [--team <id>] [--json]

The command requests cancellation for a deployment's active runs and reminder wakes. It exits nonzero if any cancellation request fails to start.

Replace event repositories

bdk event-repos <slug> [--repo <owner/name>]...  [--team <id>] [--json]

The supplied repositories replace the deployment's complete event repository list; they aren't merged with the previous list. Omit --repo to clear the list.

Upgrade a deployment

bdk upgrade <slug> [--release <id-or-version>]  [--team <id>] [--json]

--release accepts a release ID or version. Omit it to select the newest ready release. --json prints { releaseId }.

Roll back a deployment

bdk rollback <slug> [--release <id-or-version>]  [--team <id>] [--json]

rollback moves the deployment to an earlier ready release without building a new one. Omit --release to select the release before the current one. --json prints { releaseId }.

Delete a deployment

bdk delete <slug> [--team <id>] [--no-wait] [--json]

delete removes the deployment and frees its slug. It waits until the deployment is gone unless --no-wait is set.

Rotate an alias token

bdk rotate-token <slug> [--team <id>] [--json]

The old token stops working immediately. The replacement appears once; --json prints { aliasToken }.

Manage deployment secrets

bdk secrets set <slug> NAME [NAME2 ...]  [--team <id>] [--from-argv] [--json]bdk secrets list <slug> [--team <id>] [--json]bdk secrets unset <slug> NAME [--team <id>] [--json]

Pass secret names to set. On a TTY, the CLI prompts for a hidden value and ends that value at the first newline. With one name, redirected stdin is the whole value and one trailing newline is removed, so a PEM private key keeps its line breaks:

bdk secrets set my-bot GITHUB_APP_PRIVATE_KEY < ./app.private-key.pem

With several names, provide one line per name. set rejects NAME=VALUE on the command line unless --from-argv is set, because those values can enter shell history and captured terminals.

Names use UPPER_SNAKE_CASE, start with a letter, and contain at most 64 characters. Names beginning with CURSOR_ are reserved. Values contain at most 4096 bytes, and each deployment holds at most 32 secrets.

list returns names and creation times, never values. JSON output is { secretNames } for set, { secrets } for list, and { removed } for unset. Changes are available to subsequent hosted work.

Manage container images

bdk images push <local-image> --name <name> [--team <id>] [--json]bdk images list [--team <id>] [--json]bdk images rm <name> [--team <id>] [--json]

A persistent agent can run inside a container image that your team pushes and names in hosting.image. push needs Docker on your machine. It checks the local image first: the image must be linux/amd64 and have bash, git, node 22.13 or newer, and npm on PATH. The command then compresses the image and uploads it under --name.

list shows the team's images and how many the team can keep, and rm deletes one image. A deploy pins the image it uses, so after you push a new image under the same name, deploy again to pick it up.

MCP connections

Connect an MCP client

bdk mcp --url <baseUrl> [--bearer-token <token>]bdk mcp install --url <baseUrl> [--bearer-token <token>]  [--name <server-name>] [--print] [--json]
CommandContract
mcpRead newline-delimited JSON-RPC from stdin and proxy it to the selected agent's MCP endpoint. stdout is reserved for MCP messages. A target is required.
mcp installAdd the selected agent to ~/.cursor/mcp.json. --name sets the server name, --print previews the entry, and --json prints a machine-readable result. A --url entry with --bearer-token contains that token; handle printed and written copies as credentials.

Hosted deployments don't support mcp or mcp install; both report that the deployment doesn't support the command when you pass --prod.

Authorize MCP OAuth

bdk mcp oauth <connection> [--dir <path>]  [--slug <slug>] [--team <id>]

<connection> is the basename under bot/mcp-connections/ or bot/host-connections/.

ConnectionResult
defineConnection({ url, oauth: true })Open a browser PKCE flow and save tokens in mcp-auth.json under the CLI config directory.
defineConnection({ cursorAccount: true })Authorize the hosted deployment's service account through Cursor.

URL-connection tokens are bound to the resource URL; authorize again after changing it.

See Host MCP OAuth for the full setup flow.

Channel helpers

Configure Slack

bdk slack setupbdk slack create [--dir <path>] [--name <name>] [--prod]  [--slack-team <id>] [--team <id>] [--icon <url-or-file>]  [--prefix <prefix> | --no-prefix] [--channel-posts] [--json]bdk slack destroy [--dir <path>] [--prod]  [--slack-team <id>] [--team <id>] [--json]bdk slack icon <url-or-file> [--dir <path>] [--prod]  [--slack-team <id>] [--team <id>] [--json]bdk slack init --manual [--dir <path>] [--name <name>]  [--prefix <prefix> | --no-prefix] [--channel-posts]  [--install | --no-install] [--slack-team <id>] [--prod]bdk slack manifest [--dir <path>] [--name <name>]  [--env dev|prod|both] [--channel-posts] [--print]bdk slack doctor [--dir <path>]  [--prefix <prefix> | --no-prefix] [--channel <id>]... [--json]
SubcommandContract
setupPrint the setup choices without changing files.
createOpen the signed-in Cursor dashboard wizard, write the resulting token pair to .env.local, and run doctor. The development app is the default; --prod selects production. A second create overwrites the live app manifest.
destroyDelete the provisioned app. Existing local token entries remain but stop working.
iconSet an HTTPS or local PNG, JPG, or GIF icon of at most 512 KB.
init --manualWrite the channel, manifests, Slack CLI project, and setup files for a manually managed app.
manifestGenerate Slack manifests. --env defaults to both; with --print, select one environment when you need one JSON document.
doctorCheck both tokens, Socket Mode connectivity, Slack authentication, and any repeatable --channel values.

The default token prefix is the project directory name normalized to upper snake case. --no-prefix uses SLACK_BOT_TOKEN and SLACK_APP_TOKEN. Channel-post subscriptions are off by default; --channel-posts adds message events for public and private channels as required by engagement.channelPosts. Multi-agent servers need one token pair per agent.

See Slack for app consent and manual setup.

Test GitHub webhooks

bdk github forward [--dir <path>] [--slug <slug>] [--channel <id>]  [--repo owner/repo | --org <org>] [--events a,b,c]  [--url <url>] [--host <host>] [--port <n>]  [--secret <secret>] [--install]bdk github replay <pr-url-or-owner/repo#N>  [--events a,b,c | '*'] [--action <action>] [--conclusion <result>]  [--comment <body>] [--context <name>] [--dir <path>]  [--slug <slug>] [--channel <id>] [--url <url>]  [--secret <secret>] [--dry-run] [--out <dir>] [--json]bdk github events [--dir <path>] [--host <host>] [--port <n>] [--json]bdk github doctor [--install] [--json]
SubcommandContract
forwardForward live deliveries with gh webhook forward. The CLI derives URLs and events from discovered channels and can fan out to several matches.
replayRead a pull request, synthesize selected webhook payloads, and post them to matching channels. The default event is pull_request; '*' selects the channel's supported declared events.
eventsList discovered channel URLs and event sets. No channels is a successful empty result.
doctorCheck the GitHub CLI, its login, and the pinned webhook extension. --install installs or repairs the extension.

Replay supports pull_request, issue_comment, pull_request_review_comment, check_run, check_suite, workflow_run, and status. --dry-run prints without posting. --out writes fixtures and still posts unless combined with --dry-run.

Forwarding requires repository admin access, or organization owner access for --org. It uses the GitHub CLI's stored login; unset GITHUB_TOKEN and GH_TOKEN before forwarding. Replay needs only pull-request read access.

See GitHub for channel setup and live delivery.

Test GitLab webhooks

bdk gitlab replay <mr-url-or-group/project!N>  [--events a,b,c | '*'] [--action <action>]  [--conclusion <status>] [--comment <body>]  [--dir <path>] [--slug <slug>] [--channel <id>]  [--url <url>] [--host <host>] [--port <n>]  [--secret <secret>] [--dry-run] [--out <dir>] [--json]bdk gitlab events [--dir <path>] [--host <host>] [--port <n>] [--json]bdk gitlab forward [--dir <path>] [--host <host>] [--port <n>]
SubcommandContract
replayRead a merge request, synthesize selected webhook payloads, and post them to matching channels. The default event is merge_request; '*' selects the channel's declared events.
eventsList discovered GitLab channel URLs and object kinds.
forwardPrint the public-hook and tunnel recipe for live deliveries.

Replay supports merge_request, note, pipeline, and push. It requires GITLAB_TOKEN with project read access. --secret defaults to GITLAB_WEBHOOK_SECRET; --dry-run and --out follow the GitHub replay contract.

See GitLab for channel setup and self-managed hosts.

Test Bitbucket webhooks

bdk bitbucket replay <pr-url-or-workspace/repo#N>  [--events a,b,c | '*'] [--comment <body>]  [--dir <path>] [--slug <slug>] [--channel <id>]  [--url <url>] [--host <host>] [--port <n>]  [--secret <secret>] [--dry-run] [--out <dir>] [--json]bdk bitbucket events [--dir <path>] [--host <host>] [--port <n>] [--json]bdk bitbucket forward [--dir <path>] [--host <host>] [--port <n>]
SubcommandContract
replayRead a pull request, synthesize webhook payloads in the host's Cloud or Data Center format, and post them to matching channels.
eventsList discovered Bitbucket channel URLs and event keys.
forwardPrint the repository-hook and tunnel recipe for live deliveries.

Replay supports pullrequest:created, pullrequest:updated, pullrequest:comment_created, and repo:push, along with their supported Data Center forms. It requires BITBUCKET_TOKEN with pull-request read access. --secret defaults to BITBUCKET_WEBHOOK_SECRET; --dry-run and --out follow the GitHub replay contract.

See Bitbucket for Cloud and Data Center setup.

Environment variables

Credential resolution follows this order: --api-key, CURSOR_API_KEY, CURSOR_API_KEY_FILE, CURSOR_SERVICE_ACCOUNT_KEY, then the stored login.

VariableContract
CURSOR_API_KEYCursor credential.
CURSOR_API_KEY_FILEPath to a Cursor credential file.
CURSOR_SERVICE_ACCOUNT_KEYTeam service-account credential used after the API key and key-file sources.
CURSOR_API_BASE_URLBackend for login, account, deployment, and event commands.
CURSOR_BACKEND_URLBackend for BDK turns. Set it with CURSOR_API_BASE_URL when using a non-default backend.
AGENT_SERVE_CONFIG_DIROverride the CLI config directory for stored credentials and update state.
AGENT_SERVE_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER, CIDisable published-version checks when set to a non-empty value other than 0.
GITHUB_WEBHOOK_SECRETDefault signature secret for GitHub forwarding and replay.
GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, GITHUB_APP_INSTALLATION_IDGitHub App credentials for outbound API calls.
GITHUB_TOKEN, GH_TOKENToken credentials for outbound GitHub calls. Unset both for github forward.
GITLAB_TOKENToken for GitLab API reads and direct channel calls.
GITLAB_API_BASE_URLOverride the GitLab REST base URL for self-managed hosts.
GITLAB_WEBHOOK_SECRETDefault GitLab webhook token for replay and channel verification.
BITBUCKET_TOKENToken for Bitbucket API reads and direct channel calls.
BITBUCKET_API_BASE_URLOverride the Bitbucket Data Center REST base URL.
BITBUCKET_WEBHOOK_SECRETDefault Bitbucket signing secret for replay and channel verification.
SLACK_BOT_TOKEN, SLACK_APP_TOKENSlack tokens for one agent. Multi-agent servers use <PREFIX>_SLACK_BOT_TOKEN and <PREFIX>_SLACK_APP_TOKEN.

Exit status

CommandNonzero contract
No commandPrint help and exit 1. Explicit help, --help, and -h exit 0.
runFor local and running-server trajectories, exit 1 when the trajectory fails.
callExit 1 unless the response succeeds with ok: true.
skillExit 2 when the name is missing and 1 when the request fails.
trajectoryExit 1 when the reconstructed trajectory failed.
evalExit 1 for failed cases, or scored cases below threshold with --strict; exit 2 for invalid eval options or an execution with no matching cases. An empty --list succeeds.
eval statusExit 3 while the batch runs, 1 when it failed or was cancelled, and 2 for invalid usage.
chat, sessionExit 2 for documented option conflicts or missing required input.
validateExit 1 when any project diagnostic has error severity.
convert-automationExit 1 for invalid input, authentication, export, or file-write failure. Warnings and dependency-install failure don't change a successful conversion exit.
migrateExit 0 when nothing needs a migration, after starting with --no-wait, or after the agent opens a pull request. Exit 1 for invalid input, authentication or agent failure, or a completed run without a pull request.
Other commandsExit nonzero when validation, authentication, a request, or the requested operation fails.