Skip to content
Open
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
9 changes: 8 additions & 1 deletion registry/coder/modules/agent-relay-claude-code/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on each build and runs the Claude Code self-hosted runner.
```tf
module "claude_code_runner" {
source = "registry.coder.com/coder/agent-relay-claude-code/coder"
version = "0.1.1"
version = "0.2.0"
agent_id = coder_agent.main.id

# Downloads the Claude Code CLI at start when it is not in the image. Bake
Expand Down Expand Up @@ -55,6 +55,13 @@ startup and refuses to serve a pool that does not satisfy it. Every parameter
renders disabled with a "Set by Agent Relay on dispatch" placeholder; the
credential is masked.

`agent_relay_client_platform` is attribution rather than contract: the relay
stamps the surface the session was created from (`web_claude_ai`,
`claude_in_slack`, `desktop_app`, ...) and the module exposes it to the
Comment thread
Emyrk marked this conversation as resolved.
workspace as `AGENT_RELAY_CLIENT_PLATFORM` and as the `client_platform`
output, so a template can vary its setup by origin. A relay that predates the
parameter leaves it empty.

## Scripts and logs

The module runs two steps through [coder-utils](https://registry.coder.com/modules/coder/coder-utils):
Expand Down
30 changes: 30 additions & 0 deletions registry/coder/modules/agent-relay-claude-code/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
# persistent state: coderd only stores parameter values the
# template declares, and Agent Relay's dedupe and reconciliation query
# workspaces with `param:` search filters on them.
# - agent_relay_client_platform is persistent attribution: the surface
# that created the session. Stamped on every build; relays that
# predate it simply never set it.
# - agent_relay_credential, agent_relay_claude_code_lock_to_account,
# and agent_relay_attempt are ephemeral runner inputs, reset
# between builds. An ephemeral value is still recorded on the build
Expand Down Expand Up @@ -138,6 +141,20 @@ data "coder_parameter" "agent_relay_pool" {
})
}

data "coder_parameter" "agent_relay_client_platform" {
name = "agent_relay_client_platform"
display_name = "Claude Code client platform"
description = "Surface the session was created from: web_claude_ai, desktop_app, ios, android, claude_code_cli, or claude_in_slack. Agent Relay sets this when it dispatches the workspace; a human never fills it in. Exposed to the workspace as AGENT_RELAY_CLIENT_PLATFORM so a template can vary its setup by origin."
type = "string"
mutable = true
default = ""
order = 1006
styling = jsonencode({
disabled = true
placeholder = "Set by Agent Relay on dispatch"
})
}

data "coder_parameter" "agent_relay_credential" {
name = "agent_relay_credential"
display_name = "Agent Relay credential"
Expand Down Expand Up @@ -198,6 +215,14 @@ resource "coder_env" "agent_relay_claude_code_lock_to_account" {
value = data.coder_parameter.agent_relay_claude_code_lock_to_account.value
}

# Agent Relay's own variable, not the CLI's: attribution for scripts and
# tooling inside the workspace.
resource "coder_env" "agent_relay_client_platform" {
agent_id = var.agent_id
name = "AGENT_RELAY_CLIENT_PLATFORM"
value = data.coder_parameter.agent_relay_client_platform.value
}

locals {
# coder-utils requires this exact layout. Scripts land in scripts/ and
# their output in logs/; the runner state and log default to the same
Expand Down Expand Up @@ -253,3 +278,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 "client_platform" {
description = "Surface the session was created from (web_claude_ai, claude_in_slack, ...), or empty when the relay predates the parameter or the workspace was created manually."
value = data.coder_parameter.agent_relay_client_platform.value
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ run "parameter_contract" {
error_message = "attempt parameter name is part of the Agent Relay contract"
}

assert {
condition = data.coder_parameter.agent_relay_client_platform.name == "agent_relay_client_platform"
error_message = "client platform parameter name is what Agent Relay stamps"
}

# The relay reads these back off a build long after dispatch, so they
# must not be ephemeral; the rest must be, so a manual build never
# inherits a stale credential, account lock, or attempt.
Expand All @@ -48,6 +53,7 @@ run "parameter_contract" {
data.coder_parameter.agent_relay_session_id.ephemeral == false,
data.coder_parameter.agent_relay_delivery_id.ephemeral == false,
data.coder_parameter.agent_relay_pool.ephemeral == false,
data.coder_parameter.agent_relay_client_platform.ephemeral == false,
data.coder_parameter.agent_relay_credential.ephemeral == true,
data.coder_parameter.agent_relay_claude_code_lock_to_account.ephemeral == true,
data.coder_parameter.agent_relay_attempt.ephemeral == true,
Expand All @@ -63,6 +69,7 @@ run "parameter_contract" {
data.coder_parameter.agent_relay_session_id.styling,
data.coder_parameter.agent_relay_delivery_id.styling,
data.coder_parameter.agent_relay_pool.styling,
data.coder_parameter.agent_relay_client_platform.styling,
data.coder_parameter.agent_relay_credential.styling,
data.coder_parameter.agent_relay_claude_code_lock_to_account.styling,
data.coder_parameter.agent_relay_attempt.styling,
Expand Down
Loading