Problem
Launching a Cursor Cloud agent from a chat composer is a one-shot, lane-scoped action. Once several agents exist — this lane, other lanes, other ADE projects, or agents started on cursor.com — ADE has no single place to see them.
Today you have to leave ADE and hunt on cursor.com. You cannot, from one ADE surface:
- see every running / finished / failed / archived cloud agent for the connected Cursor account
- tell which ADE lane, session, project, or Linear issue an agent belongs to
- open an existing cloud agent as an ADE chat
- stop a live run that was started from a different chat or from the browser
- pull that agent's branch and artifacts into the matching lane
- see what it cost
Composer launch stays the way you start a new cloud agent. This ticket is the way you live with the fleet afterward.
What this is
A first-class ADE surface — not buried inside one chat — that is the account-wide Cursor Cloud operations view.
Think of it the way Work is the operations view for local agents: one list, grouped, filterable, with the actions you actually take on a hosted agent. It is not a second composer and it is not a Cursor iframe.
Placement
Reachable without having a particular chat selected. Natural homes: a Work companion / right pane, or a dedicated Cursor Cloud section in Work. It must still work when the current chat is local, empty, or a different provider.
Do not make this the only way to launch a new cloud agent. New launches stay in the composer (Cursor Cloud as a machine, lane-first branch, Auto-PR). This view may deep-link to a fresh composer in cloud mode, but it does not own the launch form.
Inventory
Show every cloud agent the connected Cursor account can see, not only ones ADE started.
Each row should carry:
- Cursor's own agent name (this is the title on cursor.com; ADE should not invent a second one)
- status: creating, running, finished, error, cancelled, expired, archived
- repo and branch / starting ref
- model
- age (created / last activity)
- summary / prompt snippet when Cursor provides one
- PR link when one exists
- ADE ownership when we know it: project, lane, ADE session, Linear issue
- cost / usage for that agent when Cursor's usage API returns it
Filters / sections that matter in practice:
- Active runs (creating + running) at the top, with a live affordance to stop
- Finished / failed recently
- Archived, behind an explicit toggle (off by default)
- Filter by ADE project, lane, repo, status
Empty and error states must be honest: missing Cursor API key, repo list / agent list failure, and "no agents" are three different sentences. Do not collapse a key-missing error into "no agents."
Grouping
Default grouping is ADE lane, then project. Agents ADE did not start (no metadata) fall into an "Unlinked" group keyed by repo + branch so they are still findable.
This grouping is only as good as the metadata stamped at launch (ADE session id, lane id, project id, Linear issue id on every cloud agent). Until that stamping ships, Unlinked will be the majority — the view still has to be usable in that world, it just will not be able to promise lane ownership.
Actions per agent
Open in ADE. Mirror the existing cloud agent into a new ADE chat in the matching lane (or the current lane if unlinked, with a clear warning). Replies keep executing in cloud. Cloud and local stay separate; there is no "bring this cloud agent onto this machine." A chat that already has turns cannot be promoted to cloud — Open always creates/adopts a cloud session, it never converts a local transcript.
Stop. Cancel the live run from anywhere (Agent.getRun(runId).cancel()). Works for agents started in ADE, in another ADE chat, or on cursor.com. Survives the caller disconnecting.
Pull into lane. On finish, pull the agent's branch and artifacts into the ADE lane that owns it. ADE already auto-pulls for agents launched from ADE; this view must:
- show pull status (pending / pulled / failed / not linked to a lane)
- let you trigger a pull for an unlinked or failed agent into a lane you choose
- never silently dump a foreign branch onto the wrong lane
Open in Cursor. Button that opens the agent's webUrl (cursor.com). This is the boundary for Cursor's cloud remote desktop: that desktop is real, web-only, and has no embed API. ADE does not iframe it. Cursor also has a native iOS app; that is not an embed target either. Deep link out, do not fake an in-app remote desktop.
Archive / unarchive / delete. Delete is confirm-gated. Archiving hides the agent from the default list without destroying it on Cursor's side.
Open PR. If Cursor created a PR, the row links to it. prUrl / auto-create-PR are creation-time only and cannot be added retroactively from this view — do not offer a "create PR now" action on an agent that was not launched with Auto-PR.
Freshness
The list must not depend on a timer. Status changes should arrive the same way Linear does: ADE's existing relay, HMAC-SHA256 X-Webhook-Signature, statusChange for FINISHED and ERROR only. A webhook wakes the row, refreshes that agent, and (on finish) kicks pull-into-lane.
Manual refresh stays as a fallback when webhooks are not configured yet. Automations should be able to fire on "cloud agent finished" / "cloud agent failed" from the same pipe.
A stale row is worse than a missing row: if we cannot confirm status, say so rather than leaving a spinner that looks live.
Cost
Cost belongs on this fleet view (per-agent chip) and in Settings usage/stats, plus the same per-turn usage line other runtimes already show in a cloud chat.
Cost does not belong as chips in the chat transcript. That was an explicit product call.
What this is not
- Not a second launch form. Composer owns new cloud agents (machine picker → Cursor Cloud, lane-first branch, Auto-PR chip).
- Not an in-app Cursor remote desktop. Open in Cursor is a deep link.
- Not "bring cloud to local." Cloud chats stay cloud; local chats stay local.
- Not a Cursor-native fork. The SDK has no fork API. ADE-side Fork for Cursor chats already exists on the reliability work and is out of scope here.
- Not iOS-specific. Cursor's iOS app exists; this ticket is the ADE desktop/TUI fleet surface.
Depends on (separate tickets, not this one)
This view is usable as a raw Cursor account list on day one. It becomes ADE-native only after:
- Cloud metadata stamping (session / lane / project / Linear ids on every launched agent) — without it, grouping and pull-into-lane have to ask the user.
- Webhooks on ADE's relay — without it, freshness is manual refresh only.
getUsage in Settings — without it, cost chips on the rows stay empty.
Do not block shipping a readable fleet list on those three. Do block claiming "this agent belongs to lane X" or "live without refresh" until they exist.
Acceptance
- From ADE, with a Cursor account connected, I can see every cloud agent I can see on cursor.com, including ones I did not start from this chat.
- Active runs are stoppable from this view even if the launching chat is gone.
- Opening an agent creates/adopts an ADE cloud chat; replies still run in cloud; the ADE title matches Cursor's agent name.
- Finished agents can be pulled into the owning lane, or into a lane I pick if they are unlinked.
- Open in Cursor leaves ADE and opens
webUrl. Nothing in ADE pretends to be the remote desktop.
- Archived agents are hidden until I ask for them. Delete asks first.
- A missing API key, a failed fetch, and an empty fleet are three different UI states.
- Chat transcripts do not grow cost chips as a side effect of this work.
Problem
Launching a Cursor Cloud agent from a chat composer is a one-shot, lane-scoped action. Once several agents exist — this lane, other lanes, other ADE projects, or agents started on cursor.com — ADE has no single place to see them.
Today you have to leave ADE and hunt on cursor.com. You cannot, from one ADE surface:
Composer launch stays the way you start a new cloud agent. This ticket is the way you live with the fleet afterward.
What this is
A first-class ADE surface — not buried inside one chat — that is the account-wide Cursor Cloud operations view.
Think of it the way Work is the operations view for local agents: one list, grouped, filterable, with the actions you actually take on a hosted agent. It is not a second composer and it is not a Cursor iframe.
Placement
Reachable without having a particular chat selected. Natural homes: a Work companion / right pane, or a dedicated Cursor Cloud section in Work. It must still work when the current chat is local, empty, or a different provider.
Do not make this the only way to launch a new cloud agent. New launches stay in the composer (Cursor Cloud as a machine, lane-first branch, Auto-PR). This view may deep-link to a fresh composer in cloud mode, but it does not own the launch form.
Inventory
Show every cloud agent the connected Cursor account can see, not only ones ADE started.
Each row should carry:
Filters / sections that matter in practice:
Empty and error states must be honest: missing Cursor API key, repo list / agent list failure, and "no agents" are three different sentences. Do not collapse a key-missing error into "no agents."
Grouping
Default grouping is ADE lane, then project. Agents ADE did not start (no metadata) fall into an "Unlinked" group keyed by repo + branch so they are still findable.
This grouping is only as good as the metadata stamped at launch (ADE session id, lane id, project id, Linear issue id on every cloud agent). Until that stamping ships, Unlinked will be the majority — the view still has to be usable in that world, it just will not be able to promise lane ownership.
Actions per agent
Open in ADE. Mirror the existing cloud agent into a new ADE chat in the matching lane (or the current lane if unlinked, with a clear warning). Replies keep executing in cloud. Cloud and local stay separate; there is no "bring this cloud agent onto this machine." A chat that already has turns cannot be promoted to cloud — Open always creates/adopts a cloud session, it never converts a local transcript.
Stop. Cancel the live run from anywhere (
Agent.getRun(runId).cancel()). Works for agents started in ADE, in another ADE chat, or on cursor.com. Survives the caller disconnecting.Pull into lane. On finish, pull the agent's branch and artifacts into the ADE lane that owns it. ADE already auto-pulls for agents launched from ADE; this view must:
Open in Cursor. Button that opens the agent's
webUrl(cursor.com). This is the boundary for Cursor's cloud remote desktop: that desktop is real, web-only, and has no embed API. ADE does not iframe it. Cursor also has a native iOS app; that is not an embed target either. Deep link out, do not fake an in-app remote desktop.Archive / unarchive / delete. Delete is confirm-gated. Archiving hides the agent from the default list without destroying it on Cursor's side.
Open PR. If Cursor created a PR, the row links to it.
prUrl/ auto-create-PR are creation-time only and cannot be added retroactively from this view — do not offer a "create PR now" action on an agent that was not launched with Auto-PR.Freshness
The list must not depend on a timer. Status changes should arrive the same way Linear does: ADE's existing relay, HMAC-SHA256
X-Webhook-Signature,statusChangeforFINISHEDandERRORonly. A webhook wakes the row, refreshes that agent, and (on finish) kicks pull-into-lane.Manual refresh stays as a fallback when webhooks are not configured yet. Automations should be able to fire on "cloud agent finished" / "cloud agent failed" from the same pipe.
A stale row is worse than a missing row: if we cannot confirm status, say so rather than leaving a spinner that looks live.
Cost
Cost belongs on this fleet view (per-agent chip) and in Settings usage/stats, plus the same per-turn usage line other runtimes already show in a cloud chat.
Cost does not belong as chips in the chat transcript. That was an explicit product call.
What this is not
Depends on (separate tickets, not this one)
This view is usable as a raw Cursor account list on day one. It becomes ADE-native only after:
getUsagein Settings — without it, cost chips on the rows stay empty.Do not block shipping a readable fleet list on those three. Do block claiming "this agent belongs to lane X" or "live without refresh" until they exist.
Acceptance
webUrl. Nothing in ADE pretends to be the remote desktop.