Skip to content
Coder Docs

Set up Agent Relay

Deploy Agent Relay against your Coder deployment with a service account, provisioners, and the Helm chart.

On this page

Note

Agent Relay is in beta and requires a Premium license.

This guide is for Coder administrators who deploy Agent Relay against an existing Coder deployment. It covers the steps that are the same for every provider: the service account, provisioners, template rules, installation, and verification. Provider-specific steps live on the Claude Code and Cursor pages.

Before you begin

Important

Only a user with the Coder owner role can create service accounts and mint their tokens.

You need:

  • A Coder deployment with a Premium license, on version 2.39 or later.
  • Agent Relay v0.14.0 or later.
  • Somewhere to run the Agent Relay container: a Kubernetes cluster that you can reach with kubectl and helm, or a Docker host.
  • The Coder CLI, signed in as an owner.
  • An account with the provider you want to serve. Refer to the requirements on the Claude Code or Cursor page.

Plan your deployment

Choose one of these layouts:

  • One relay per deployment. One relay serves every organization and both providers with a single service account.
  • One relay per organization. Each relay has its own service account and its own provider credentials, which isolates organizations from each other. For example, a deployment with three organizations runs three relays.

In either layout, never give two relays the same provider credentials. Both relays claim the same sessions and compete over the same workspaces.

Plan provisioner capacity for each pool, because every pool you add can start more builds at once. Refer to Provision capacity for Agent Relay.

Create a service account

Agent Relay needs no site-wide role. At startup, it checks that its service account has the permissions that its pools need.

In every organization that a pool names, the service account needs these permissions:

ResourceActions
organization_memberread
workspacecreate, read, start, update, delete
workspace_secretcreate

On every template that a pool names, the service account needs read and use. By default, a new template grants use, which includes read, to its organization's Everyone group, so a service account in the organization already has both. Grant them in the template's permissions only if the template doesn't give the Everyone group access.

The organization-admin role in each organization covers all of these permissions. To grant less, create an organization-scoped custom role with only the permissions above.

  1. Create the service account in the organization that Agent Relay serves:

    coder users create --service-account --username agent-relay --org <org>
  2. Add the service account to every other organization that a pool names.

  3. Assign the organization-admin role, or your custom role, in each of those organizations.

  4. Create a long-lived token for the service account:

    RELAY_TOKEN=$(coder tokens create --user agent-relay --name agent-relay-token --lifetime 8760h)
  5. If you install with Helm, store the token in a Kubernetes secret:

    kubectl create secret generic agent-relay-coderd \
      --namespace coder \
      --from-literal=session-token="$RELAY_TOKEN"

    The Helm chart doesn't accept the token as a plain value.

Agent Relay verifies organization permissions at startup. A missing organization permission stops the daemon. For example, a service account without the workspace_secret create permission stops it with missing coderd capabilities [set-workspace-secrets[<org id>]]. Agent Relay verifies template permissions per pool. A missing template permission degrades only that pool, and the pool recovers when you fix the template.

Why Agent Relay needs some of these permissions:

  • workspace update lets it extend the autostop deadline of workspaces with an active session. It checks for this permission in every organization at startup, even if no template uses keepalive.
  • workspace_secret create lets it deliver each session's provider credential to the workspace as an ephemeral workspace build secret. Agent Relay checks the Coder version once, at startup, to decide how to deliver credentials, so restart Agent Relay after you upgrade Coder.

Provision capacity for Agent Relay

Agent Relay builds run on your Coder provisioners, and time spent waiting for a free provisioner counts against each session's build deadline. We recommend dedicated external provisioners for Agent Relay templates, so relay builds don't compete with human workspace builds.

Each provider page explains how to size capacity for its pools:

To run a dedicated set of provisioners on Kubernetes:

  1. Create a provisioner key with a tag for Agent Relay:

    coder provisioner keys create relay-key --org <org> --tag workload=agent-relay

    Copy the key from the output. Coder shows it once.

  2. Store the key in a Kubernetes secret:

    kubectl create secret generic agent-relay-provisioner-key \
      --namespace coder \
      --from-literal=key="<provisioner-key>"
  3. Create a provisioner-values.yaml file:

    coder:
      env:
        - name: CODER_URL
          value: "https://coder.example.com"
      # One provisioner runs one build at a time.
      replicaCount: 10
    provisionerDaemon:
      pskSecretName: ""
      keySecretName: agent-relay-provisioner-key
      keySecretKey: key

    The provisioners pick up the workload=agent-relay tag from the key.

  4. Install the coder-provisioner Helm chart with a version that matches your Coder server version:

    helm install coder-provisioner coder-v2/coder-provisioner \
      --namespace coder \
      --version <coder-version> \
      --values provisioner-values.yaml
  5. When you push an Agent Relay template, use the same tag:

    coder templates push <template> --provisioner-tag workload=agent-relay

If no provisioner with a matching tag is online, relay builds stay pending.

These coder-provisioner chart values affect Agent Relay:

ValueEffect
coder.replicaCountThe number of provisioner pods, which sets concurrent build capacity. The default is 1.
provisionerDaemon.keySecretName, keySecretKeyThe secret that holds the provisioner key. The key carries the provisioner's tags.
coder.resources, nodeSelector, tolerations, affinityWhere pods run and how large they are. Plan for 1 vCPU and 1 GB of memory per 2 concurrent builds.
provisionerDaemon.terminationGracePeriodSecondsHow long a stopping pod has to finish its build. The default is 600.

The chart can install more than once under different release names, so you can run one set of provisioners for people and a tagged set for Agent Relay.

Prepare a workspace template

Each pool builds from one template. Every Agent Relay template must:

  • Include the provider's Agent Relay module from the Coder Registry: coder/agent-relay-claude-code or coder/agent-relay-cursor.
  • Declare the module's agent_relay_status metadata item on its coder_agent resource. Agent Relay reads this value to decide when to delete the workspace. If you rename or omit the key, Agent Relay never deletes the workspace.
  • Set allow_user_cancel_workspace_jobs = true. Agent Relay cancels in-flight builds when it rebuilds or tears down a workspace. Without this setting, the pool degrades.
  • Provide a default for every template parameter, or set a value in the pool's template_parameters.

The provider pages show the module block for each provider.

We also recommend that you:

  • Use a dedicated template. Relay workspaces are ephemeral and machine-driven. A separate template keeps quotas, access control, and activity policy for people from interfering.
  • Use quotas to control spend. Relay builds count against the session owner's quota, the same as any other workspace. Coder enforces quota during the build, so a build that exceeds the owner's quota fails and Agent Relay deletes the workspace. Cursor shows the build error in the developer's chat. Claude Code doesn't show it, so the reason appears only in Agent Relay's logs.
  • Keep builds fast. Pre-pull images, avoid persistent volumes, and bake the provider CLI into the image with install_cli = false.
  • Own your workspace image. ghcr.io/coder/agent-relay-workspace:latest is a reference image: codercom/enterprise-base:ubuntu with both provider CLIs, rebuilt weekly. Use it as the base of your own image and add your tooling.
  • Restrict workspace egress. Agent sessions run unattended. Allow only the hosts on the provider page and the internal services that sessions need.
  • Configure Git credentials in the template. Coder can supply each session owner's Git credentials through external authentication, but the template must declare the provider. Refer to the source control section on each provider page.

Start the worker after workspace setup

Agent Relay hands a workspace to the provider as soon as its build succeeds, not when the workspace agent is ready. The provider module starts the worker right away, so the agent can run commands while your startup scripts are still cloning repositories or installing tools.

To make the worker wait, put the setup that sessions need in coder_script resources or modules. Then add a coder_script_order rule that runs the Agent Relay module after them:

resource "coder_script" "setup" {
  agent_id     = coder_agent.main.id
  display_name = "Workspace setup"
  run_on_start = true
  timeout      = 300
  script       = file("${path.module}/setup.sh")
}

data "coder_script_order" "relay_worker" {
  rule {
    phase = "start"
    # Use module.claude_code_runner for Claude Code.
    run   = ["module.cursor_worker"]
    after = ["coder_script.setup"]
  }
}
  • Set phase = "start", because the module also has a shutdown script.
  • Script ordering requires the Coder Terraform provider v2.20.0 or later.
  • Script ordering also requires Coder v2.39.0 or later for the control plane, provisioners, and workspace agents. On earlier versions, Coder ignores the rule without an error, and the worker starts right away.
  • Coder can't order the startup_script attribute of coder_agent. Move setup steps that the worker depends on into coder_script resources.
  • If a prerequisite fails, Coder skips the module's scripts and the worker never starts. To start the worker even when setup fails, set requires = "completion" on the rule.
  • The session waits while prerequisites run. Set a timeout on each prerequisite, and keep setup well under 15 minutes, after which Agent Relay deletes a workspace whose worker hasn't started.

Configure provider pools

Follow the steps on the provider page to create the provider credential, add the module to your template, and write the pool configuration:

Then return to this page to install Agent Relay.

Install Agent Relay

ArtifactLocationVersioning
Imageghcr.io/coder/agent-relayX.Y.Z, X.Y, latest per release
Helm chartoci://ghcr.io/coder/chart/coder-agent-relayMatches the image it deploys

Both are public and need no pull credentials. For every option and Helm value, refer to the Agent Relay configuration reference.

  1. Create a values.yaml file with your Coder URL, the token secret from step 1, and the pools and secrets from the provider page:

    coderd:
      url: https://coder.example.com
      sessionToken:
        secretName: agent-relay-coderd
        key: session-token
    
    pools:
      claudeCode: []   # Refer to the Claude Code page.
      cursor: []       # Refer to the Cursor page.
    
    secretEnv: []      # One entry per pool secret_env.
  2. Install the chart:

    helm install agent-relay oci://ghcr.io/coder/chart/coder-agent-relay \
      --namespace coder \
      --version <version> \
      --values values.yaml

The chart runs a single replica with strategy: Recreate and creates no Kubernetes RBAC. Agent Relay talks to the Coder control plane over HTTPS and never calls the Kubernetes API.

Pin a chart version in production instead of tracking latest.

Agent Relay release binaries for running as a systemd service aren't published yet.

Verify the deployment

Agent Relay fails fast at startup. An invalid token, an unlicensed deployment, an unsupported Coder version, or a missing organization permission stops the daemon with an explicit message.

  1. Read the daemon's logs:

    # Kubernetes
    kubectl logs -n coder deploy/coder-agent-relay
    
    # Docker
    docker logs <container>
  2. Confirm that the authenticated against coderd log line shows build_secrets=true.

  3. Confirm that each pool logs that it's ready.

    A Claude Code pool logs template verified, polling, and a Cursor pool logs pool verified, serving.

  4. Confirm that Agent Relay is ready. With Helm, the pod becomes Ready only after at least one pool passes verification. With Docker, run curl -sS http://localhost:2112/readyz, which prints ok when a pool is serving and lists any pool that is still verifying or has failed.

  5. Start a session from the provider's client and select the pool.

  6. In Coder, confirm that a workspace is created for your user.

  7. End the session and confirm that Agent Relay deletes the workspace.

For logs, metrics, and troubleshooting, refer to Monitor Agent Relay.

Workspace lifecycle

The provider module publishes the worker's state through the agent_relay_status metadata item. Agent Relay's reaper reads it on each sweep:

  • When the worker exits normally, Agent Relay deletes the workspace.
  • When the worker fails or disappears, Agent Relay deletes the workspace and records the failure.
  • When a build fails or is canceled, Agent Relay deletes the workspace on the next sweep.
  • Agent Relay deletes a workspace that is still building or not started after 15 minutes.

Keep these Coder settings in mind for relay templates:

  • Autostop: Agent Relay extends the autostop deadline of a workspace while a session is attached, if the template declares the module's agent_relay_session_attached metadata item. Without that item, the template's autostop schedule stops relay workspaces at the deadline, even in the middle of a session. Refer to Keep attached workspaces running.
  • Stopped workspaces: Agent Relay doesn't delete stopped workspaces. They remain until someone deletes them or dormancy auto-deletion removes them.
  • Quotas: Relay builds count against the session owner's quota. Refer to the template recommendations above.
  • Deleted work: Agent Relay deletes the workspace when the session ends. Unpushed commits and files are lost.

Keep attached workspaces running

To keep autostop from stopping a workspace in the middle of a session, add the module's agent_relay_session_attached metadata item next to agent_relay_status:

resource "coder_agent" "main" {
  # ...
  metadata {
    key          = "agent_relay_session_attached"
    display_name = "Session attached"
    # Use module.claude_code_runner for Claude Code.
    script       = module.cursor_worker.session_attached_metadata_script
    interval     = 30
    timeout      = 5
  }
}

On each sweep, Agent Relay reads this item. When the value is attached and the sample is less than two minutes old, Agent Relay extends a deadline that is less than 35 minutes away to 45 minutes from now. To change these durations, set --reap-keepalive-refresh-before and --reap-keepalive-bump-by.

  • Keep the metadata interval well under two minutes, or Agent Relay can't rely on a fresh sample.
  • The image needs curl, and the Cursor module also needs awk.
  • Agent Relay doesn't extend a workspace past its template's maximum deadline, and doesn't extend workspaces that have no autostop deadline.
  • Keepalive requires module version 1.0.0 or later and Agent Relay v0.14.0 or later.

Workspace names start with a provider prefix: cc- for Claude Code and cur- for Cursor.

Upgrade from early access

Agent Relay v0.14.0 and module version 1.0.0 deliver provider credentials as workspace build secrets, which need Coder 2.39 or later. Early access module versions, agent-relay-claude-code 0.4.0 or earlier and agent-relay-cursor 0.7.0 or earlier, don't support build secrets. Upgrade Coder, Agent Relay, and every Agent Relay template in the same maintenance window. If you need help planning the upgrade, contact Coder.

  1. Upgrade Coder to 2.39 or later.

  2. Grant the service account workspace update and workspace_secret create in every organization that a pool names.

    Agent Relay v0.14.0 doesn't start without them. The organization-admin role already includes both.

  3. Convert each Cursor pool's idle_release_timeout from seconds to a duration, such as 10m for 600.

    0 still turns off idle release.

  4. Upgrade Agent Relay to v0.14.0 or later.

  5. Update every Agent Relay template to module version 1.0.0.

Learn more