From 4478bf86627710e139aefebd73c67d7293d7229d Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 24 Sep 2026 17:49:30 +0000 Subject: [PATCH 1/3] feat(coder/agent-relay-cursor): export the cloud session id Templates can open the Cursor cloud session from a coder_app when Agent Relay stamps agent_relay_session_id. --- registry/coder/modules/agent-relay-cursor/main.tf | 5 +++++ registry/coder/modules/agent-relay-cursor/main.tftest.hcl | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/registry/coder/modules/agent-relay-cursor/main.tf b/registry/coder/modules/agent-relay-cursor/main.tf index 2b5f7aae5..c56181e7a 100644 --- a/registry/coder/modules/agent-relay-cursor/main.tf +++ b/registry/coder/modules/agent-relay-cursor/main.tf @@ -313,3 +313,8 @@ output "dispatched" { description = "Whether this workspace was spawned by Agent Relay (credential set) or manually (empty)." value = data.coder_parameter.agent_relay_credential.value != "" } + +output "session_id" { + description = "Cursor cloud agent id stamped in agent_relay_session_id. Empty when a person created the workspace. A template uses this for an external coder_app at https://cursor.com/agents/." + value = data.coder_parameter.agent_relay_session_id.value +} diff --git a/registry/coder/modules/agent-relay-cursor/main.tftest.hcl b/registry/coder/modules/agent-relay-cursor/main.tftest.hcl index 36340084d..83fa4ba47 100644 --- a/registry/coder/modules/agent-relay-cursor/main.tftest.hcl +++ b/registry/coder/modules/agent-relay-cursor/main.tftest.hcl @@ -179,6 +179,11 @@ run "worker_wiring" { condition = output.dispatched == false error_message = "a build with no credential was not dispatched by Agent Relay" } + + assert { + condition = output.session_id == "" + error_message = "a manual build has no Cursor cloud session id" + } } run "computer_use_off_by_default" { From 3d06ade336c7b5e9cd0a535709afe1cc5dd05b7f Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 24 Sep 2026 18:10:31 +0000 Subject: [PATCH 2/3] feat(coder/agent-relay-cursor): open the cloud agent in Cursor Web and Desktop The module adds the buttons when Agent Relay stamps a session id, using Cursor's names for the two clients. --- .../modules/agent-relay-cursor/README.md | 10 ++++++++ .../coder/modules/agent-relay-cursor/main.tf | 25 ++++++++++++++++++- .../agent-relay-cursor/main.tftest.hcl | 5 ++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/registry/coder/modules/agent-relay-cursor/README.md b/registry/coder/modules/agent-relay-cursor/README.md index 5266ba931..e1c7e757f 100644 --- a/registry/coder/modules/agent-relay-cursor/README.md +++ b/registry/coder/modules/agent-relay-cursor/README.md @@ -40,6 +40,16 @@ The `agent_relay_status` metadata block is required. It has to live on the `coder_agent`, which the module cannot declare; the relay reads it to decide when to reap the workspace. +When Agent Relay stamps `agent_relay_session_id`, the module adds two external +apps. Cursor's docs call the clients Cursor Web and Cursor Desktop: + +- **Open in Cursor Web** opens the cloud agent at `https://cursor.com/agents/`. +- **Open in Cursor Desktop** opens it with + `cursor://anysphere.cursor-deeplink/background-agent?bcId=`. + +A workspace a person creates by hand has no session id, so neither button is +created. + ## Requirements - The Cursor CLI (`agent`) must be in the workspace. `install_cli` (default diff --git a/registry/coder/modules/agent-relay-cursor/main.tf b/registry/coder/modules/agent-relay-cursor/main.tf index c56181e7a..528f8589a 100644 --- a/registry/coder/modules/agent-relay-cursor/main.tf +++ b/registry/coder/modules/agent-relay-cursor/main.tf @@ -315,6 +315,29 @@ output "dispatched" { } output "session_id" { - description = "Cursor cloud agent id stamped in agent_relay_session_id. Empty when a person created the workspace. A template uses this for an external coder_app at https://cursor.com/agents/." + description = "Cursor cloud agent id stamped in agent_relay_session_id. Empty when a person created the workspace." value = data.coder_parameter.agent_relay_session_id.value } + +# Cursor's own names for the two clients that open a cloud agent: +# Cursor Web (cursor.com/agents) and Cursor Desktop. A hand-created +# workspace has no session id, so neither button exists. +resource "coder_app" "cursor_web" { + count = data.coder_parameter.agent_relay_session_id.value != "" ? 1 : 0 + agent_id = var.agent_id + slug = "cursor-web" + display_name = "Open in Cursor Web" + icon = "/icon/cursor.svg" + url = "https://cursor.com/agents/${data.coder_parameter.agent_relay_session_id.value}" + external = true +} + +resource "coder_app" "cursor_desktop" { + count = data.coder_parameter.agent_relay_session_id.value != "" ? 1 : 0 + agent_id = var.agent_id + slug = "cursor-desktop" + display_name = "Open in Cursor Desktop" + icon = "/icon/cursor.svg" + url = "cursor://anysphere.cursor-deeplink/background-agent?bcId=${data.coder_parameter.agent_relay_session_id.value}" + external = true +} diff --git a/registry/coder/modules/agent-relay-cursor/main.tftest.hcl b/registry/coder/modules/agent-relay-cursor/main.tftest.hcl index 83fa4ba47..354a86165 100644 --- a/registry/coder/modules/agent-relay-cursor/main.tftest.hcl +++ b/registry/coder/modules/agent-relay-cursor/main.tftest.hcl @@ -184,6 +184,11 @@ run "worker_wiring" { condition = output.session_id == "" error_message = "a manual build has no Cursor cloud session id" } + + assert { + condition = length(coder_app.cursor_web) == 0 && length(coder_app.cursor_desktop) == 0 + error_message = "a manual build has no cloud agent, so neither Cursor client button is created" + } } run "computer_use_off_by_default" { From cfb3f29400ec2688f2748027c904bcaad91fbebc Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 24 Sep 2026 18:28:39 +0000 Subject: [PATCH 3/3] chore: bump module versions (minor) --- registry/coder/modules/agent-relay-cursor/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/agent-relay-cursor/README.md b/registry/coder/modules/agent-relay-cursor/README.md index e1c7e757f..08f2c9a43 100644 --- a/registry/coder/modules/agent-relay-cursor/README.md +++ b/registry/coder/modules/agent-relay-cursor/README.md @@ -16,7 +16,7 @@ parameters the relay stamps on each build and runs the Cursor CLI worker. ```tf module "cursor_worker" { source = "registry.coder.com/coder/agent-relay-cursor/coder" - version = "0.2.0" + version = "0.3.0" agent_id = coder_agent.main.id # Downloads the Cursor CLI at start when it is not in the image. Bake