Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion registry/coder/modules/agent-relay-cursor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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/<id>`.
- **Open in Cursor Desktop** opens it with
`cursor://anysphere.cursor-deeplink/background-agent?bcId=<id>`.

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
Expand Down
28 changes: 28 additions & 0 deletions registry/coder/modules/agent-relay-cursor/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,31 @@ 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."
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
}
10 changes: 10 additions & 0 deletions registry/coder/modules/agent-relay-cursor/main.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ 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"
}

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" {
Expand Down
Loading