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
| Command | Contract |
|---|---|
help, --help, -h | Print top-level help |
serve | Serve one or more agents over HTTP |
dev | Serve agents with local-development behavior |
docs | Serve the documentation bundled with @cursor/bdk |
init | Scaffold a BDK project |
convert-automation | Export a Cursor Automation into a project |
migrate | Move an early-alpha project to architecture v2 through a pull request |
install-skills | Refresh the bundled coding-agent skills |
info | Print the discovered project surface |
validate | Check project diagnostics and set the exit status |
manifest | Print deployment metadata as JSON |
version | Print the installed package version |
update | Upgrade the installed CLI |
login | Sign the host in to Cursor |
logout | Remove the stored Cursor credential |
whoami | Show the active Cursor credential |
Session and eval commands
| Command | Contract |
|---|---|
chat | Talk to a running agent |
resume | Reattach chat to a previous session |
run | Start or continue work on a local, running, or hosted agent |
call | Call a server tool without a model turn |
skill | Read an authored skill without a model turn |
logs | Follow or dump agent logs |
sessions | List sessions |
session | Inspect a session or start a hosted session turn |
cost | Report token usage and estimated cost |
playground | Open an agent's playground |
trajectory | Summarize a saved event stream |
eval | List, run, inspect, or cancel evals |
Managed hosting commands
| Command | Contract |
|---|---|
deploy | Deploy one or more agents |
deployments | List deployments |
deployment | Inspect one deployment |
stop | Stop a deployment |
start | Start a stopped deployment |
kill | Stop a deployment, cancel its runs, and lock deploys |
unlock-deploys | Let a killed deployment deploy again |
cancel-runs | Cancel active runs and reminder wakes |
event-repos | Replace a deployment's event repositories |
upgrade | Move a deployment to a release |
rollback | Move a deployment to an earlier release |
delete | Delete a deployment |
rotate-token | Replace a deployment's alias token |
secrets | Set, list, or remove deployment secrets |
images | Push, list, or remove container images for persistent agents |
Connection and channel commands
| Command | Contract |
|---|---|
mcp | Proxy an agent's MCP endpoint over stdio |
mcp install | Add the agent to an MCP client config |
mcp oauth | Authorize an MCP connection |
slack | Provision and check Slack channel apps |
github | Forward, replay, and inspect GitHub webhooks |
gitlab | Replay and inspect GitLab webhooks |
bitbucket | Replay and inspect Bitbucket webhooks |
Targets
Commands that send requests support these targets:
| Target | Selection | Commands |
|---|---|---|
| Ephemeral local server | Omit --url and --prod | run, call, skill, eval |
| Running server | Pass --url <baseUrl> | chat, resume, run, call, skill, eval, logs, sessions, session, cost, playground, mcp |
| Default local server | Omit --url and --prod; uses http://127.0.0.1:3000 | chat, resume, logs, sessions, session, cost, playground |
| Hosted deployment | Pass --prod | run, 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.
| Option | Contract |
|---|---|
--dir <path> | Select the project root. The default is the current directory. |
--url <baseUrl> | Use a running agent instead of local project discovery. |
--prod | Use 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. |
--json | Request 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>]...| Option | Contract |
|---|---|
--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 multi | Mount projects at /<slug>/v1/* and /<slug>/playground, with an index at /. This is the default. |
--mode single | Mount one project at /v1/* and /playground. Declared peers are omitted with a warning unless --peers-url is set. |
--dev | Disable 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-anonymous | Admit callers as one anonymous principal. Use it only behind a trusted network boundary. |
--allow-anonymous-cursor-github | Let anonymous callers use sessions with a Cursor account's repository-scoped GitHub credential. Requires an authenticating proxy. |
--allow-anonymous-cursor-account-mcp | Let anonymous callers use Cursor account MCP connections. Requires an authenticating proxy. |
--allow-anonymous-grokbot | Let 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-schedules | Disable schedule firing outside dev mode. |
--no-playground | Skip the playground. |
--no-docs | Skip the documentation site at /docs. |
--cursor-events | Receive 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 3000It 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 mode | Behavior |
|---|---|
TTY without --message | Open an interactive REPL. |
TTY with --message | Send the message, then keep the REPL open. |
Non-TTY with --message | Send one turn and exit. |
Non-TTY without --message | Read 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>]| Option | Contract |
|---|---|
--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-events | Skip the NDJSON trace. |
--text | Print a compact trajectory instead of JSON. |
--timeout-ms <n> | Stop waiting after a positive number of milliseconds. There is no default timeout. |
--no-stream | Hide live tool and reply progress on stderr. |
--dry-run | Start 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>]| Option | Contract |
|---|---|
| No output option | Print a compact trajectory. |
--text | Select the compact trajectory explicitly. |
--json | Print the trajectory object. |
--events | Print { 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.
| Option | Contract |
|---|---|
--list | List matching cases without running them. --list --json prints an array. |
--tag <tag> | Select a tag. Repeat the option for OR matching. |
--json | Print { ok, passed, failed, scored, skipped, strict, results }. |
--verbose | Stream t.log lines and reply snippets. |
--no-stream | Hide live progress on stderr. |
--strict | Treat 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-artifacts | Skip artifacts for an ephemeral local run. |
--skip-report | Ignore reporters from eval files and the eval config during an ephemeral local run. |
--out <file.json> | Also write the full result JSON. |
--no-wait | Return 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.
| Option | Contract |
|---|---|
--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=value | Answer a template question without a prompt. Repeat for multiple answers. |
--json | Skip 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.
| Option | Contract |
|---|---|
--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-run | Print the planned files, defaults, exclusions, unmapped behavior, placeholders, secret names, warnings, and setup steps without writing files or installing dependencies. |
--json | Never 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.
| Option | Contract |
|---|---|
--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-wait | Print the cloud agent URL and return after the agent starts. |
--json | Print 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.
Print a deployment manifest
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| Command | Contract |
|---|---|
login | Use 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. |
whoami | Show the active credential and its source. --json returns the same identity as JSON. |
logout | Remove the stored credential file. It doesn't revoke the API key; revoke the key in the Cursor dashboard. |
Print the version
bdk version [--json]bdk --versionbdk -VText output is the version number. --json prints
{ name, version }.
Update the CLI
bdk updateupdate 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.
| Option | Contract |
|---|---|
--slug <slug> | Select one project and set its deployment slug. Under a folder of several agents, this deploys that one agent. |
--all | Deploy 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-wait | Return after the deployment request is accepted. |
--json | Print 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.pemWith 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]| Command | Contract |
|---|---|
mcp | Read 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 install | Add 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/.
| Connection | Result |
|---|---|
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]| Subcommand | Contract |
|---|---|
setup | Print the setup choices without changing files. |
create | Open 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. |
destroy | Delete the provisioned app. Existing local token entries remain but stop working. |
icon | Set an HTTPS or local PNG, JPG, or GIF icon of at most 512 KB. |
init --manual | Write the channel, manifests, Slack CLI project, and setup files for a manually managed app. |
manifest | Generate Slack manifests. --env defaults to both; with --print, select one environment when you need one JSON document. |
doctor | Check 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]| Subcommand | Contract |
|---|---|
forward | Forward live deliveries with gh webhook forward. The CLI derives URLs and events from discovered channels and can fan out to several matches. |
replay | Read 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. |
events | List discovered channel URLs and event sets. No channels is a successful empty result. |
doctor | Check 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>]| Subcommand | Contract |
|---|---|
replay | Read 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. |
events | List discovered GitLab channel URLs and object kinds. |
forward | Print 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>]| Subcommand | Contract |
|---|---|
replay | Read a pull request, synthesize webhook payloads in the host's Cloud or Data Center format, and post them to matching channels. |
events | List discovered Bitbucket channel URLs and event keys. |
forward | Print 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.
| Variable | Contract |
|---|---|
CURSOR_API_KEY | Cursor credential. |
CURSOR_API_KEY_FILE | Path to a Cursor credential file. |
CURSOR_SERVICE_ACCOUNT_KEY | Team service-account credential used after the API key and key-file sources. |
CURSOR_API_BASE_URL | Backend for login, account, deployment, and event commands. |
CURSOR_BACKEND_URL | Backend for BDK turns. Set it with CURSOR_API_BASE_URL when using a non-default backend. |
AGENT_SERVE_CONFIG_DIR | Override the CLI config directory for stored credentials and update state. |
AGENT_SERVE_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER, CI | Disable published-version checks when set to a non-empty value other than 0. |
GITHUB_WEBHOOK_SECRET | Default signature secret for GitHub forwarding and replay. |
GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, GITHUB_APP_INSTALLATION_ID | GitHub App credentials for outbound API calls. |
GITHUB_TOKEN, GH_TOKEN | Token credentials for outbound GitHub calls. Unset both for github forward. |
GITLAB_TOKEN | Token for GitLab API reads and direct channel calls. |
GITLAB_API_BASE_URL | Override the GitLab REST base URL for self-managed hosts. |
GITLAB_WEBHOOK_SECRET | Default GitLab webhook token for replay and channel verification. |
BITBUCKET_TOKEN | Token for Bitbucket API reads and direct channel calls. |
BITBUCKET_API_BASE_URL | Override the Bitbucket Data Center REST base URL. |
BITBUCKET_WEBHOOK_SECRET | Default Bitbucket signing secret for replay and channel verification. |
SLACK_BOT_TOKEN, SLACK_APP_TOKEN | Slack tokens for one agent. Multi-agent servers use <PREFIX>_SLACK_BOT_TOKEN and <PREFIX>_SLACK_APP_TOKEN. |
Exit status
| Command | Nonzero contract |
|---|---|
| No command | Print help and exit 1. Explicit help, --help, and -h exit 0. |
run | For local and running-server trajectories, exit 1 when the trajectory fails. |
call | Exit 1 unless the response succeeds with ok: true. |
skill | Exit 2 when the name is missing and 1 when the request fails. |
trajectory | Exit 1 when the reconstructed trajectory failed. |
eval | Exit 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 status | Exit 3 while the batch runs, 1 when it failed or was cancelled, and 2 for invalid usage. |
chat, session | Exit 2 for documented option conflicts or missing required input. |
validate | Exit 1 when any project diagnostic has error severity. |
convert-automation | Exit 1 for invalid input, authentication, export, or file-write failure. Warnings and dependency-install failure don't change a successful conversion exit. |
migrate | Exit 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 commands | Exit nonzero when validation, authentication, a request, or the requested operation fails. |