The proto/ directory is machine-written: Cursor's release automation
regenerates it on every SDK release and tags the result. Any hand edit is
overwritten by the next release, so pull requests must not touch
proto/. proto/manifest.json records which release a checkout carries
(protocol, sdkVersion, and the source commit it was generated from).
Tags vX.Y.Z track SDK releases one-to-one. For a given version you get, all
mutually consistent:
- the protos at the tag in this repo;
@cursor/sdk@X.Y.Zon npm andcursor-sdk==X.Y.Zon PyPI;- the standalone bridge archives attached to the
GitHub release for tag
vX.Y.Z(cursor-sdk-bridge-standalone-<os>-<arch>.tar.gz).
Pin your adapter's codegen to a tag, and prefer running a bridge whose
manifest.json sdkVersion matches it. That said, exact matching is not
required — see the compatibility promise below.
sdk.v1 evolves additively. Within the v1 protocol:
- existing fields are never renumbered, retyped, or repurposed;
- removals are handled with
reservedstatements, not reuse; - new RPCs, messages, fields, enum values, stream envelope cases, and capability strings may be added at any time.
Compatibility is checked with buf breaking semantics (WIRE_JSON,
configured in the root buf.yaml) before every release. An incompatible
change would ship as a new sdk.v2 package alongside sdk.v1, not as an
edit to it.
What this demands of adapters (the standard proto3 rules):
- ignore unknown fields when deserializing — including JSON, where some
runtimes reject unknown keys by default (pass the equivalent of
ignore_unknown_fields); - tolerate unrecognized enum values, envelope cases,
SdkMessage.typediscriminators, and capability strings; - treat discovery-line JSON the same way: unknown keys are additions.
An adapter generated from an older tag keeps working against a newer bridge,
and vice versa; new functionality simply is not visible until you regenerate.
Use SdkBridgeControlService.GetVersion (protocol_version, capabilities)
when you need to gate on bridge features at runtime.