Skip to content

fix(registry/coder/modules): clean relay state on stop and start - #1212

Merged
Emyrk merged 3 commits into
mainfrom
fix/relay-workspace-start-state
Oct 29, 2026
Merged

Emyrk merged 3 commits into
mainfrom
fix/relay-workspace-start-state

Conversation

@Emyrk

@Emyrk Emyrk commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Problem

A relay workspace can restart with its previous runner state on a persistent home volume. The old working state can read as orphaned, an old done can look like the new run's result, and a surviving supervisor or worker can compete with the new one. Agent Relay can act on that stale status before the new run publishes its own (RELAY-71).

Change

  • Both Claude Code and Cursor modules render their startup and run_on_stop cleanup from one source per module. On graceful stop, cleanup signals verified supervisors and workers, waits up to 10 seconds after TERM and 5 seconds after KILL, and removes state. It does not publish a marker that permits a new launch. Templates need at least 30 seconds of runtime shutdown grace for the 20-second stop-hook timeout plus agent shutdown.
  • On every agent start, the pre-install step immediately clears old state, attempts the same bounded process cleanup, clears state again, and publishes a fresh generation. The start step also creates or rotates a generation if pre-install did not finish or was skipped. Without a fresh credential it reports idle instead of a prior run's result. Cursor removes its stale token before reporting idle.
  • Never signal a PID unless its boot ID and /proc start time match its record. Keep unverifiable records for a later attempt.

Availability tradeoff: Startup fails open if the old process survives or cannot be verified. Two runners may overlap. A surviving old supervisor can race to write stale status or, for Cursor, remove a new worker's shared token after its generation check. This interference is explicitly accepted for this failure mode, rather than blocking a new work order. A stop hook can also be skipped or cut short; startup cleanup remains the fallback.

Scope: This is module-side cleanup, not a complete RELAY-71 fix. Agent Relay still needs new-build status-settling grace because it may sweep before cleanup or fresh metadata. The reaper work is separate.

Validation

  • Claude Code: 34 container tests, 24 Terraform tests.
  • Cursor: 41 container tests, 24 Terraform tests.
  • bun run fmt, targeted Prettier and Terraform formatting checks, bun run check:validate for both modules, and git diff --check.
  • Stop-mode marker behavior was mutation-tested: reversing it made the new stop tests fail for both providers.
Decision log for reviewers
  • Keep cleanup before install in the existing coder-utils pre-install step, and add a separate coder_script with run_on_stop from the same per-module source. The stop mode never writes a fresh launch marker.
  • Track supervisor and worker independently. Match PID, boot ID, and /proc start time before TERM or KILL; no pidfd helper. Remove status before signalling, wait, then remove it again.
  • Fail open on cleanup verification failure: attempt bounded cleanup, log and retain unverifiable records, but allow a new generation to start even when an old runner survives or cleanup never ran. This deliberately favors availability over preventing duplicates; stale status and Cursor token interference from a surviving old supervisor are accepted risks.
  • Give the stop hook a 20-second timeout and document a minimum 30-second workspace runtime shutdown grace. Hard stops cannot guarantee the hook runs. The separate relay reaper-side settling grace remains necessary.

Generated by Coder Agents for @Emyrk.

@linear-code

linear-code Bot commented Oct 26, 2026

Copy link
Copy Markdown

RELAY-71

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Module Scorecard Check

coder/agent-relay-claude-code: 70 → 63

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

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

Presentation & Onboarding — 12 / 17

Criterion Max Score Notes
Configuration-mode examples 12 12 README gives worked examples for the major configuration axes: install_cli true/false (BYOI vs. download), additional_args, release_idle_session_min override, and health_port override, each with a code block and sensible defaults called out.
Visual preview 5 0 No image, GIF, or video anywhere in the README.

Credential Hygiene — 12 / 20

Criterion Max Score Notes
Secrets marked sensitive 16 8 agent_relay_credential uses ephemeral = true and styling.mask_input = true, but no resource in main.tf sets sensitive = true (not present on coder_parameter or coder_env here). README never shows an inline/placeholder key, so half credit for avoiding inline secrets without the literal sensitive-flag convention.
Non-hardcoded auth path 4 4 Credentials are never pasted by a human; Agent Relay stamps a single-use JWT into a disabled, masked parameter and the module wires it to SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET via coder_env — a documented non-manual auth path.

Restricted-Environment Readiness — 13.5 / 20

Criterion Max Score Notes
Mirrorable artifact source 5 0 install.sh.tftpl hardcodes curl https://claude.ai/install.sh -fsSL | bash; no module variable overrides this download URL.
Bring-your-own binary 10 10 install_cli = false fully skips the download, documented in the README ("Bake the CLI into the image and set this to false for faster workspaces") and in Requirements.
Egress transparency 3 1.5 claude.ai/install.sh is mentioned in the Requirements section and in script comments, but there is no dedicated "network/egress" section enumerating contacted endpoints — scattered mentions cap this at half.
Runs without sudo 2 2 install.sh.tftpl, start.sh.tftpl, and cleanup.sh.tftpl never invoke sudo; all operations (curl install, process management, file writes) run as the invoking user.

Engineering Quality — 10 / 10

Criterion Max Score Notes
Input quality 6 6 Every variable has a clear description and default; several carry validation blocks (cli_binary regex, exit_if_unused_min, release_idle_session_min 0–10080 bound, health_port 0–65535, additional_args reserved-flag and newline checks).
Test coverage 4 4 Large main.tftest.hcl covers parameter contract, env wiring, script rendering business logic; main.test.ts runs full end-to-end container tests against a stubbed CLI covering lifecycle, cleanup races, idle release, and injection safety.

Agent Integration — 10 / 25

Criterion Max Score Notes
AI governance 10 0 No mention of Coder AI Gateway or Agent Firewall anywhere in the README.
Dashboard entry point 5 0 No coder_app resource or documentation of one; the module only renders coder_script/metadata outputs.
Session continuity 5 5 "Idle session release" section explicitly documents native resume: an idle session is released server-side and "the user's next message resumes the session on a fresh runner."
Managed configuration 5 5 base_dir variable is documented as the configured workdir (CLI's --base-dir), with rationale for why the module always sets its own value rather than the CLI default.

Overall — 63 / 100

Raw 57.5 / 92 → round(57.5 / 92 × 100) = 63

coder/agent-relay-cursor: 51 → 49

⚠️ Score regression: 51 → 49 (-2). Check the drilldown for which criteria dropped.

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

Presentation & Onboarding — 6 / 17

Criterion Max Score Notes
Configuration-mode examples 12 half README gives a primary usage example plus additional_args and management_addr override snippets, but computer_use/share_desktop (a major opt-in mode requiring extra image packages) and install_cli = false are only discussed in prose (Requirements section), with no dedicated code example for each mode.
Visual preview 5 0 No image, GIF, or video anywhere in the README.

Agent Integration — 5 / 25

Criterion Max Score Notes
AI governance 10 0 No mention of Coder AI Gateway or Agent Firewall anywhere in the README; auth/routing is handled entirely through Agent Relay's own claim/session-token model, not Coder's governance primitives.
Dashboard entry point 5 full coder_app.cursor_web and coder_app.cursor_desktop are declared and clearly documented ("Open in Cursor Web" / "Open in Cursor Desktop"), conditioned on a dispatched session.
Session continuity 5 0 No documented resume/session-ID continuity or persistent session manager (tmux/screen/boo) for reconnects; the idle-release/session-attachment machinery governs reaping, not reconnect continuity.
Managed configuration 5 0 No documented support for managed MCP, settings, policies, or workdir configuration.

Credential Hygiene — 12 / 20

Criterion Max Score Notes
Secrets marked sensitive 16 half agent_relay_credential uses ephemeral = true and styling = { mask_input = true } rather than a literal sensitive = true attribute; no coder_env resource is marked sensitive either. README examples never inline a literal secret, which is good, but the formal "sensitive" marking mechanism specified by the rubric isn't used.
Non-hardcoded auth path 4 full Extensive "Worker credential" section documents that the service-account key never leaves Agent Relay, only a short-lived, claim-scoped session token reaches the workspace via --auth-token-file, never on the command line or in the template.

Restricted-Environment Readiness — 12 / 20

Criterion Max Score Notes
Mirrorable artifact source 5 0 install.sh.tftpl hardcodes curl https://cursor.com/install -fsSL | bash. No module variable (e.g. cli_binary, management_addr) overrides the download URL — cli_binary only overrides the binary path/name, not the install source.
Bring-your-own binary 10 full install_cli = false (documented in the top example and the Requirements section) skips the download entirely and expects the CLI pre-baked in the image, with cli_binary to point at it.
Egress transparency 3 0 No dedicated network/egress/air-gapped section; cursor.com/install, cursor.com/agents, and the cursor:// deeplink are mentioned only incidentally in unrelated sections, never enumerated together.
Runs without sudo 2 full All scripts (install.sh.tftpl, start.sh.tftpl, cleanup.sh.tftpl) run entirely as the invoking user with no sudo calls anywhere.

Engineering Quality — 10 / 10

Criterion Max Score Notes
Input quality 6 full Variables have detailed descriptions and sensible defaults, plus strong validation blocks (cli_binary command-safety regex, management_addr host:port + port-range checks, share_desktop requires computer_use, additional_args rejects reserved flags/newlines, serving_log_pattern rejects empty string).
Test coverage 4 full main.tftest.hcl covers parameter contract, script wiring, and business logic extensively via plan-time assertions; main.test.ts runs real container-based end-to-end tests of install/start/cleanup lifecycle, PID/boot-id identity verification, and SIGTERM/SIGKILL escalation.

Overall — 49 / 100

Raw 45 / 92 → round(45 / 92 × 100) = 49

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.

@Emyrk
Emyrk force-pushed the fix/relay-workspace-start-state branch from 8ed3996 to 869b131 Compare October 27, 2026 16:42
@Emyrk
Emyrk marked this pull request as ready for review October 28, 2026 19:36
@Emyrk
Emyrk requested a review from matifali October 28, 2026 19:36
@Emyrk
Emyrk marked this pull request as draft October 28, 2026 19:43
@Emyrk Emyrk changed the title fix(registry/coder/modules): clear stale relay state before startup fix(registry/coder/modules): clean relay state on stop and start Oct 28, 2026
@Emyrk
Emyrk marked this pull request as ready for review October 28, 2026 22:02

@matifali matifali left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this been tested?

@Emyrk

Emyrk commented Oct 29, 2026

Copy link
Copy Markdown
Member Author

Has this been tested?

Yes. I've run tests before and after the stop script work.

@Emyrk
Emyrk merged commit 56c11a0 into main Oct 29, 2026
5 checks passed
@Emyrk
Emyrk deleted the fix/relay-workspace-start-state branch October 29, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants