Skip to content

feat(coder/agent-relay-claude-code)!: make additional_args a list of strings - #1205

Merged
matifali merged 3 commits into
mainfrom
claude/agent-relay-claude-code-args-list
Oct 23, 2026
Merged

matifali merged 3 commits into
mainfrom
claude/agent-relay-claude-code-args-list

Conversation

@matifali

Copy link
Copy Markdown
Member

Description

Changes additional_args, added in v0.3.0 (coder/registry#1198), from a map(string) of flag to value into a list(string) with one element per argument.

Why: a map can't repeat a flag, as 35C4n0r pointed out on coder/registry#1202. Worse, Terraform doesn't reject a repeated key: { "--header" = "a", "--header" = "b" } silently becomes { "--header" = "b" }, so the first value disappears without an error. A list also reads like the command line, can be pasted from --help, and keeps the order you write.

module "claude_code_runner" {
  source          = "registry.coder.com/coder/agent-relay-claude-code/coder"
  version         = "0.4.0"
  agent_id        = coder_agent.main.id
  additional_args = ["--some-flag", "value", "--some-flag", "another value", "--another-flag"]
}
  • Verbatim, in order: each element is passed to claude self-hosted-runner as exactly one argument, in the order written, after the flags the module sets and before --exec-path. As before, it's base64-encoded into the start script and shell-quoted with printf %q into the supervisor, so spaces, quotes, $VAR and backticks are never split or expanded.
  • Validation: elements must be non-empty and must not contain newlines.
  • Flags the module sets are still rejected: --capacity, --base-dir, --exit-if-unused-min, --exec-path. Each element is checked with any =value stripped, so --capacity=2 is caught too. The keep-in-sync comments in main.tf and start.sh.tftpl are unchanged.

Type of Change

  • New module
  • New template
  • Bug fix
  • Feature/enhancement
  • Documentation
  • Other

Module Information

Path: registry/coder/modules/agent-relay-claude-code
New version: v0.4.0
Breaking change: [x] Yes [ ] No — additional_args changes type from map(string) to list(string). To migrate, rewrite { "--flag" = "value", "--bare" = "" } as ["--flag", "value", "--bare"]. The module is pre-1.0, so this ships as a minor bump; v0.3.0 has only been out a few hours, and its tag is left as it is.

Testing & Validation

  • Tests pass: terraform test, 12 passed. Updated: empty default; base64 encoding of a repeated flag in order; rejecting a newline; rejecting --capacity=2.
  • Container test in main.test.ts updated to cover a repeated flag with spaces and quotes. It can't run here because the runner has no Docker daemon.
  • Code formatted (bun fmt); ./scripts/terraform_validate.sh passes
  • Changes tested locally: rendered the start script with terraform console and ran it against a stub claude. The argv was self-hosted-runner --capacity 1 --base-dir … --exit-if-unused-min 10 --name <two words $HOME \id`> --name <it's "q"> --verbose --exec-path …`, with each element unchanged and in order.

Related Issues

Follows up the review on coder/registry#1202.


Generated by Claude Code

matifali and others added 2 commits October 23, 2026 03:02
…strings

additional_args was a map of flag to value, which cannot repeat a flag:
a repeated key silently keeps only the last value. It is now a list with
one element per argument, passed in order, so a flag can repeat. Flags
the module sets are still rejected, with or without =value.

BREAKING CHANGE: additional_args changes type from map(string) to
list(string). Rewrite { "--flag" = "value" } as ["--flag", "value"].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R2TMgCPW8SL8kUCB28L4dt
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Module Scorecard Check

coder/agent-relay-claude-code: 59 → 52

⚠️ Score regression: 59 → 52 (-7). Check the drilldown for which criteria dropped.

Theme Before After
Presentation & Onboarding 12 / 17 6 / 17
Integration 0 / 25 0 / 25
Credential Hygiene 20 / 20 20 / 20
Restricted-Environment 12 / 20 12 / 20
Engineering Quality 10 / 10 10 / 10
Overall 59 / 100 52 / 100
Full scorecard for this PR
Presentation & Onboarding Agent Integration Credential Hygiene Restricted-Environment Readiness Engineering Quality Overall
6 / 17 0 / 25 20 / 20 12 / 20 10 / 10 52 / 100
Drilldown

Presentation & Onboarding — 6 / 17

Criterion Max Score Notes
Configuration-mode examples 12 6 Primary example (default install_cli = true) and additional_args example are both present with sensible defaults. However, the "baked-in CLI" mode (install_cli = false), which the README explicitly calls "the recommended and fastest path," has no dedicated example block—it is only mentioned in a code comment and the variable description.
Visual preview 5 0 No image, GIF, or video embedded in the README. The frontmatter icon field is a module icon, not a preview of the module in action.

Agent Integration — 0 / 25

Criterion Max Score Notes
AI governance 10 0 No mention of Coder AI Gateway or Agent Firewall anywhere in the README or code. The module relies on Agent Relay's work-order JWT for auth but does not document how Coder governs routing or policy enforcement via AI Gateway or Agent Firewall.
Dashboard entry point 5 0 No coder_app resource declared or documented. The module is a headless runner dispatched by Agent Relay; there is no user-facing dashboard entry point.
Session continuity 5 0 No documentation of resuming an existing session across reconnects or relaunches. The agent_relay_session_id parameter is for Agent Relay's internal deduplication, not user-facing session resume. No mention of tmux, screen, boo, or native resume.
Managed configuration 5 0 No documented support for managed MCP, settings, policies, or workdir config. base_dir sets a checkout directory but is not a managed-configuration mechanism. No MCP server config, no settings file, no policy enforcement.

Credential Hygiene — 20 / 20

Criterion Max Score Notes
Secrets marked sensitive 16 16 agent_relay_credential uses mask_input = true in its styling (confirmed in main.tf and asserted in main.tftest.hcl). README examples contain no inline secrets—only agent_id = coder_agent.main.id and structural parameters.
Non-hardcoded auth path 4 4 The credential is a single-use work-order JWT injected by Agent Relay at dispatch time. README states: "Agent Relay sets this when it dispatches the workspace; a human never fills it in." No raw key is pasted into the template.

Restricted-Environment Readiness — 12 / 20

Criterion Max Score Notes
Mirrorable artifact source 5 0 The install URL https://claude.ai/install.sh is hardcoded in install.sh.tftpl. No module input variable overrides this download URL. cli_binary changes the expected binary path, not the source URL. No variable exists to point the installer at an internal mirror.
Bring-your-own binary 10 10 install_cli = false disables the download entirely. The install script checks command -v ${cli_binary} and skips if present. README: "Bake the CLI into the image and set this to false for faster workspaces." The start script also adds ~/.local/bin to PATH unconditionally so a baked-in CLI is found.
Egress transparency 3 0 No dedicated README section enumerating external endpoints. claude.ai/downloads.claude.ai (install) and Anthropic API (runtime) are inferable from code and variable descriptions but not listed in a network/air-gapped section.
Runs without sudo 2 2 All three scripts (install.sh.tftpl, start.sh.tftpl, status.sh.tftpl) operate exclusively under $HOME paths. No sudo invocation anywhere. The installer writes to ~/.local/bin; the runner writes to $HOME/.coder-modules/....

Engineering Quality — 10 / 10

Criterion Max Score Notes
Input quality 6 6 All 8 variables have clear descriptions and sensible defaults. cli_binary has a regex validation preventing shell metacharacters. exit_if_unused_min validates non-negative integer. additional_args validates non-empty, no newlines, and rejects reserved flags (--capacity, --base-dir, --exit-if-unused-min, --exec-path).
Test coverage 4 4 main.tftest.hcl covers parameter contract (names, ephemeral flags, styling/masking), runner wiring, install CLI behavior, additional_args encoding, path overrides, and serving_log_pattern safety. main.test.ts runs 10+ end-to-end tests in containers with stub binaries: idle state, terminal-state persistence, missing-CLI detection, BYO-CLI discovery, download skip, file layout, detached runner with permissions wrapper, additional_args ordering, exit-code recording, custom paths, and shell-injection resistance of serving_log_pattern.

Overall — 52 / 100

Raw 48 / 92 → round(48 / 92 × 100) = 52

Tip

You can run this locally by telling your agent: "review this module against .github/scorecard/SCORECARD.md".


Scored against SCORECARD.md with solstice-1. Language-model scores are advisory.

@matifali
matifali requested review from 35C4n0r and dluman October 23, 2026 06:04
@35C4n0r 35C4n0r added the version:minor Add to PRs requiring a minor version upgrade label Oct 23, 2026
@matifali
matifali merged commit 4a9630e into main Oct 23, 2026
5 checks passed
@matifali
matifali deleted the claude/agent-relay-claude-code-args-list branch October 23, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

version:minor Add to PRs requiring a minor version upgrade

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants