> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensorlake.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Run Cursor Cloud Agents on Tensorlake Sandboxes

> Use Tensorlake sandboxes as the self-hosted machines for Cursor Cloud Agents. Cursor runs the agent loop; every command, file edit, and repo checkout runs in a sandbox you control.

[Cursor Cloud Agents](https://cursor.com/docs/cloud-agent/self-hosted) can run on self-hosted machines. Cursor keeps the agent loop and the model in its cloud. The machine, where commands run, files change, and repositories get checked out, moves into a Tensorlake sandbox you own.

A small **orchestrator** claims Cursor requests and gives each one its own worker sandbox. The orchestrator also runs in a Tensorlake sandbox, so nothing stays running on your laptop. When a worker goes idle its sandbox suspends. A follow-up message resumes the same sandbox with the checkout and caches intact.

```mermaid theme={null}
graph LR
    C["Cursor cloud<br/>agent loop + request queue"]
    O["Orchestrator<br/>one per pool, runs in a Tensorlake sandbox"]
    W["Worker sandbox<br/>one per agent, runs the Cursor agent worker"]

    C -->|"pending requests"| O
    O -->|"create · suspend · resume · start worker"| W
    W -->|"outbound HTTPS"| C
```

## Why Tensorlake

* **Suspend and resume.** A worker sandbox suspends when the agent goes idle and resumes in about a second when a follow-up arrives. Memory, filesystem, and the repository checkout stay intact. You do not pay for idle machines and the agent does not wait for a cold start.
* **One sandbox per agent.** Each request gets its own microVM. Agents cannot see each other's code or credentials.
* **No inbound ports.** Workers connect out to Cursor over HTTPS. Nothing listens on the sandbox.
* **Egress control.** Set an allowlist so a worker can reach only Cursor and your git host.
* **Desktop workers.** Build the worker image from `tensorlake/ubuntu-vnc` and the agent can drive a browser and a desktop. See [Computer use](#computer-use).

## Prerequisites

Cursor:

* A Cursor **Enterprise** team. Cursor offers self-hosted pools only on Enterprise.
* A **service-account API key** from **Dashboard → Settings → API Keys → Service Accounts**. Pool workers reject personal and team keys.
* A team administrator who can enable self-hosted machines and GitHub token minting.
* The Cursor GitHub App connected at the team level, with access to each repository the agents will work on.

<Note>
  No Enterprise team? A personal key on any plan can run one long-lived worker in one sandbox. See [My Machines in the repo README](https://github.com/tensorlakeai/cursor-cloud-agents-tensorlake#my-machines).
</Note>

Tensorlake:

* An account and API key from [cloud.tensorlake.ai](https://cloud.tensorlake.ai).
* The `tl` CLI, optional: `curl -fsSL https://tensorlake.ai/install | sh`. This guide uses it to list sandboxes and read worker logs.

Local machine:

* Python 3.10 or newer and [uv](https://docs.astral.sh/uv/).
* Nothing stays running here after setup.

## Set up Cursor

A Cursor team administrator does this once:

1. Open **Dashboard → Cloud Agents → Self-Hosted**.
2. Enable **Self-hosted Machines**.
3. Enable GitHub token minting for self-hosted pool workers.
4. Give the Cursor GitHub App access to each repository.

## Quickstart

The reference implementation is [tensorlakeai/cursor-cloud-agents-tensorlake](https://github.com/tensorlakeai/cursor-cloud-agents-tensorlake). One command does the whole setup.

```bash theme={null}
git clone https://github.com/tensorlakeai/cursor-cloud-agents-tensorlake
cd cursor-cloud-agents-tensorlake
uv sync --all-extras
uv run cursor-tl-up
```

`cursor-tl-up` asks for the Cursor and Tensorlake keys once and saves them to `.env`. Then it checks the Cursor key, registers the pool, builds or reuses both images, launches the orchestrator sandbox, and waits until the controller reports `watching`.

The pool is a Cursor Team Pool: the queue that self-hosted workers serve. Its name comes from `CURSOR_POOL`, default `tensorlake`. This is the name you pick at cursor.com/agents under **Remote Machines**. Worker sandboxes are named `cursor-<worker-id>`.

The command is idempotent. Run it again to repair a suspended orchestrator sandbox or a dead process. It skips steps that are already done.

Useful options:

```bash theme={null}
uv run cursor-tl-up --computer-use    # desktop worker image; workers start with --computer-use
uv run cursor-tl-up --repo-url URL    # serve one repository only
uv run cursor-tl-up --any-repo        # let Cursor clone after the claim
uv run cursor-tl-up --rebuild         # rebuild the orchestrator image after a code change
```

By default the pool serves every repository the Cursor GitHub App can reach. For the difference between the default, `--repo-url`, and `--any-repo`, and for the step-by-step version of this setup, see [Repositories in the repo README](https://github.com/tensorlakeai/cursor-cloud-agents-tensorlake#repositories).

### Keep the orchestrator awake

The orchestrator sandbox has no idle timeout of its own, but Tensorlake suspends a named sandbox after your plan's maximum idle window. A suspended orchestrator cannot claim requests. Schedule the launcher on an always-on machine so a suspended orchestrator is resumed and re-checked. The command is idempotent.

```cron theme={null}
*/15 * * * * cd /path/to/cursor-cloud-agents-tensorlake && uv run cursor-tl-orchestrator-sandbox >/dev/null 2>&1
```

Keep the interval shorter than your plan's idle window.

## Submit a request

1. Open [cursor.com/agents](https://cursor.com/agents).
2. Pick the repository. In `any-repo` mode pick **Any repo** instead.
3. Open the machine picker, choose **Remote Machines**, and pick **tensorlake**.
4. Send the task. In `any-repo` mode name the repository in the prompt.

You can also send a request from the API:

```bash theme={null}
uv run cursor-tl-pool agent "Add a unit test for the parser" --repo https://github.com/acme/widgets
```

Watch it land:

```bash theme={null}
tl sbx ls                                                        # a cursor-<worker-id> sandbox appears
uv run cursor-tl-orchestrator-sandbox --logs                     # claim, spawn, worker start
tl sbx exec cursor-<worker-id> tail -n 50 /var/log/cursor-tl/worker.log
```

After the session ends, the worker waits `WORKER_IDLE_RELEASE_SECS` (default 300 seconds) and exits. The orchestrator then suspends the sandbox. A follow-up message resumes it. A sandbox suspended for longer than `SESSION_RETENTION_SECS` (default one day) is terminated.

## Computer use

Cursor agents can drive a desktop and a browser on Linux workers. Run `cursor-tl-up --computer-use`, or set `WORKER_COMPUTER_USE=true` in `.env` before you build the worker image. The worker image is then built from [`tensorlake/ubuntu-vnc`](/sandboxes/computer-use) and each worker starts with `--computer-use`. No inbound port opens.

Set `WORKER_SHARE_DESKTOP=view` or `view_and_control` to let authorized viewers watch the agent desktop from Cursor.

Test it with a task such as "open a browser, visit example.com, and take a screenshot". Desktop workers need at least 4096 MB of memory, which is the default `SANDBOX_MEMORY_MB`.

## Troubleshooting

* **"No self-hosted worker matches the requested labels".** The request was sent to the **Any repo** row, and the pool runs in default mode. Pick the repository in the web picker instead, or start the pool with `--any-repo`.
* **Request stays queued.** Run `uv run cursor-tl-orchestrator-sandbox --status`. If the sandbox is suspended, run `uv run cursor-tl-up` again and set up the [keep-alive cron](#keep-the-orchestrator-awake). Then check that the pool name matches `CURSOR_POOL`, that **Self-hosted Machines** is enabled, and that `--logs` shows the controller connected. `uv run cursor-tl-pool pending` lists what Cursor is waiting on.
* **Controller rejects the key.** Only an Enterprise service-account key starts pool workers. A personal key works only with My Machines.
* **Workspace is empty after a run.** Read `/var/log/cursor-tl/checkout.log` in the worker sandbox. Confirm GitHub token minting is enabled and the GitHub App has access to the repository. HTTPS remotes only.
* **`POST /v1/agents` returns 403 `integration_not_connected`.** The request named a repository, and the Cursor GitHub integration is not connected to the team. A team admin connects it at [cursor.com/dashboard/integrations](https://cursor.com/dashboard/integrations).
* **A follow-up landed on a new sandbox.** The reconnect window lapsed. Raise it with `uv run cursor-tl-pool register --ready-timeout 1800`, which updates the existing pool. `cursor-tl-up --ready-timeout` applies only when it creates the pool. Or check `--logs` for a failed resume.
* **A failed spawn left a claimed request.** Run `uv run cursor-tl-pool release <request-id>` so Cursor re-queues it.

More cases, including split orchestrators and idle workers that stay running, are in [Troubleshooting in the repo README](https://github.com/tensorlakeai/cursor-cloud-agents-tensorlake#troubleshooting).

## Next steps

<CardGroup cols={2}>
  <Card title="Reference implementation" icon="github" href="https://github.com/tensorlakeai/cursor-cloud-agents-tensorlake">
    Step-by-step setup, My Machines, operations commands, configuration, and design notes.
  </Card>

  <Card title="Cursor: Self-Hosted Machines" icon="book" href="https://cursor.com/docs/cloud-agent/self-hosted">
    Cursor's own documentation for pools, workers, and the Cloud Agents API.
  </Card>

  <Card title="Sandbox lifecycle" icon="arrows-rotate" href="/sandboxes/lifecycle">
    The suspend and resume model that keeps idle workers cheap.
  </Card>

  <Card title="Computer Use" icon="desktop" href="/sandboxes/computer-use">
    The desktop image that powers `--computer-use` workers.
  </Card>
</CardGroup>
