Skip to content

fix(cli): name the host in messages when mounted as agent-relay file - #510

Merged
AgentRelayBot merged 3 commits into
mainfrom
fix/mounted-program-name
Sep 19, 2026
Merged

AgentRelayBot merged 3 commits into
mainfrom
fix/mounted-program-name

Conversation

@AgentRelayBot

@AgentRelayBot AgentRelayBot commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Closes #509. Found while testing the published agent-relay@12.2.4 mount end to end.

The problem

$ npm i agent-relay@12.2.4          # note: no relayfile binary
$ agent-relay file writeback status
error: credentials not found at ~/.relayfile/credentials.json;
       run relayfile login --api-key for self-hosted credentials or pass --token

relayfile isn't on their PATH — they installed agent-relay. The advice is unfollowable.

Help never had this problem: it's rendered from the declared command spec rather than forwarded, so agent-relay file --help cannot print Usage: relayfile .... Error text is written by the Go binary at runtime and isn't covered by that.

The fix

The binary has no way to know it was reached through a host, so the surface tells it — RELAYFILE_PROGRAM_NAME on the child env, read by programName(), defaulting to relayfile when unset or blank.

direct:   run relayfile login --api-key …
mounted:  run agent-relay file login --api-key …
blank:    run relayfile login --api-key …     (falls back)

Fixed at all five user-facing sites in cmd/relayfile-cli/main.go, not just the two reachable today (writeback status, seed), so a message that becomes reachable later is already right.

On the test

It drives a real spawn through the real resolver with a fixture binary that echoes the variable back, rather than stubbing the spawn — following the pattern in binary-output.test.ts. The value has to survive the env the surface actually constructs, and there's a second case for a caller supplying its own env, since a host passing one must not silently drop the name.

Mutation-verified — reverting the spawn to plain env fails both:

× tells the binary it was reached through agent-relay file
× sets it even when the caller supplies its own env

go vet clean, gofmt clean, tsc --noEmit clean, and the Credential|Workspace|Messaging|Background Go suites pass.

Alternative considered

Rewriting the strings in the surface's io layer. Cheaper, but string-matching error text is brittle and stops working silently the moment a message is reworded. Putting the name where the messages are written means new messages are correct by construction.

🤖 Generated with Claude Code


Note

Low Risk
User-facing strings and spawn env only; no auth, sync, or data-path changes. Direct relayfile invocations keep the default name.

Overview
When the Relayfile CLI runs behind agent-relay file, user-facing text no longer hardcodes relayfile for “run this next” guidance.

The Go binary reads RELAYFILE_PROGRAM_NAME via a new programName() helper (default relayfile when unset). Usage strings, help, setup/login/mount/writeback errors, and similar messages now use that name. The TypeScript relay CLI surface sets the env to agent-relay file on every child spawn so mounted users get followable commands like agent-relay file login.

Tests lock the contract: Go usage printers must not mention bare relayfile when the env is set (while keeping literal service paths like relayfile-listen.service), TS tests verify the env survives surface spawns and align byte-for-byte comparisons with the mounted naming behavior.

Reviewed by Cursor Bugbot for commit 167a64d. Bugbot is set up for automated code reviews on this repo. Configure here.

Review in cubic

Closes #509.

`agent-relay file` mounts this binary through @relayfile/sdk's Relay CLI
surface. Someone who arrived that way installed `agent-relay`, not
`relayfile`, so six messages sent them to a binary they do not have:

    $ agent-relay file writeback status
    error: credentials not found at ~/.relayfile/credentials.json;
           run relayfile login --api-key for self-hosted credentials …

Help never had this problem — it is rendered from the declared command spec
rather than forwarded, so `agent-relay file --help` cannot print
`Usage: relayfile …`. Error text is written by the Go binary at runtime and
was not covered by that.

The binary cannot know how it was reached, so the surface tells it:
RELAYFILE_PROGRAM_NAME, set on the child env, read by programName(), which
falls back to "relayfile" when unset or blank. Direct users keep seeing the
name they typed.

Fixed at all five user-facing sites rather than only the reachable two, so
a message that becomes reachable later is already correct.

The test drives a real spawn through the real resolver with a fixture binary
that echoes the variable back, rather than stubbing the spawn: the value has
to survive the env the surface actually builds, including when a caller
supplies its own. Mutation-verified — dropping the env fails both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Session-Id: d458bd97-53d8-4f02-be9c-48b67b93c916
@coderabbitai

coderabbitai Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 4915c2ec-ebf0-4508-9635-22effa77aa75


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Devin Review

Comment thread cmd/relayfile-cli/main.go
Comment on lines +81 to +85
func programName() string {
if name := strings.TrimSpace(os.Getenv(programNameEnv)); name != "" {
return name
}
return "relayfile"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Mounted hints name missing binary

When mounted, several runtime hints still print relayfile, bypassing programName(). Examples include invalid workspace, setup completion, integration connection, and dev guidance. Users without the standalone binary receive commands they cannot run.

Learn more

The mounted TypeScript surface sets RELAYFILE_PROGRAM_NAME to agent-relay file. The Go binary reads that value through programName(), but only the newly edited call sites use it. Other reachable runtime guidance still embeds relayfile, so the environment contract does not fix those messages.

Example: A user installs only agent-relay and runs agent-relay file integration connect github. After connecting, runIntegrationConnect prints Run relayfile mount ...; that command is unavailable, while agent-relay file mount ... works.

Recommended fix: Route every user-facing command hint through a shared formatter based on programName(). At minimum, update the empty-name branch in agentRelayMessagingOnlyWorkspaceError.Error, agentRelayInvalidWorkspaceKeyError.Error, runSetupWithOptions, runIntegrationConnect, runDev, mount/status guidance, and stuck-event guidance. Preserve hard-coded agent-relay commands where they intentionally invoke the host rather than Relayfile.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread cmd/relayfile-cli/main.go
@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Relayfile Eval Review

Run: .relayfile/evals/runs/2026-09-19T00-02-30-056Z-HEAD-provider
Mode: provider
Git SHA: ee18362

Passed: 4 | Needs human: 0 | Reviewable: 0 | Missing output: 0 | Failed: 0 | Skipped: 0

Human Review Cases

No reviewable human-review cases captured Relayfile output.

Review found the previous commit's fix was a fraction of the problem. It
corrected five sites located by grepping for "run relayfile"; Devin and
Bugbot both pointed out that the same advice appears in other phrasings —
usage lines, setup completion, integration connect, dev guidance, the
supervisor help block, and the nameless branch of the messaging-only error,
which still hardcoded "relayfile setup" while the same sentence's login
advice used programName().

The lesson is that a grep for one phrasing cannot bound this. So:

  - 44 `Usage: relayfile …` prints and 38 `usage: relayfile …` errors now
    format through programName()
  - 8 multi-line raw-string help blocks templated, including the top-level
    usage, `listen`, and `supervisor`
  - the remaining instruction sites: setup completion, integration connect,
    dev guidance, writeback stuck guidance, the login deprecation warning,
    and the empty-name setup branch

Deliberately untouched, because they are not instructions:

  - `relayfile-listen.service` and `com.relayfile.listen.plist` are real
    paths on disk, identical whoever invokes us; a blanket rename would
    have broken them
  - "delegated relayfile credentials" and "relayfile workspace id" are
    nouns describing what is missing

The test asserts the class rather than any message. It runs every usage
printer with the host name set and fails on a pattern, because the leak was
never in one place. It also pins the two service filenames, and that a
direct user still sees "relayfile".

That test immediately found five more leaks than review had named, and then
a sixth: a bare `relayfile` with no verb, in the top-level usage, which both
my pattern and the test's first pattern missed. The test regex now covers a
bare mention too. Mutation-verified in both directions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Session-Id: d458bd97-53d8-4f02-be9c-48b67b93c916
@AgentRelayBot

Copy link
Copy Markdown
Contributor Author

Both right, and the finding is bigger than either comment. Fixed in 0f03ead.

Bugbot — the nameless branch of agentRelayMessagingOnlyWorkspaceError did hardcode relayfile setup while the same sentence's login advice used programName(). Fixed.

Devin — the broader point is the correct one, and it invalidates how I found the original five. I grepped for run relayfile / run `relayfile and declared "all five user-facing sites". The same advice appears in many other phrasings I never searched for.

What was actually wrong

  • 44 Usage: relayfile … prints and 38 usage: relayfile … errors
  • 8 multi-line raw-string help blocks — top-level usage, listen, supervisor
  • setup completion, integration connect, dev guidance, writeback stuck guidance, the login deprecation warning, the empty-name setup branch

All now format through programName().

Deliberately untouched

  • relayfile-listen.service, com.relayfile.listen.plist — real paths on disk, identical whoever invokes us. A blanket rename breaks them.
  • delegated relayfile credentials, relayfile workspace id — nouns describing what is missing, not commands.

The test is the actual deliverable

Asserting any single message would have been useless here — the leak was never in one place. It runs every usage printer with the host name set and fails on a pattern, plus pins the two service filenames and that a direct user still sees relayfile.

It earned that immediately: it found five more leaking printers than review had named (printUsage, printListenUsage, printWorkspaceUsage, printIntegrationUsage, printDigestUsage), and then a sixth my own fix had missed — a bare relayfile with no verb in the top-level usage, which slipped past both my regex and the test's first one. The pattern now covers bare mentions; mutation-verified in both directions.

Verified

MOUNTED:  error: usage: agent-relay file read [WORKSPACE] PATH
          agent-relay file supervisor manages the listen daemon…
            On Linux it writes ~/.config/systemd/user/relayfile-listen.service   ← preserved

DIRECT:   error: usage: relayfile read [WORKSPACE] PATH

A full sweep of all 23 mounted subcommands, with and without bad args, leaves only relayfile credentials — the noun. go vet, gofmt, and the TestUsage|Credential|Workspace|Messaging|Background|Listen suites all pass.

🤖 Generated with Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0f03ead. Configure here.

Comment thread cmd/relayfile-cli/main.go
Three suites spawn the binary directly and compare it to the surface. They
exist to prove argv routes through unchanged — but they used whole-output
equality as the proxy, so they failed on the one difference the mount is
supposed to make: mounted, the binary names the host rather than itself.

    expected 'Usage: agent-relay file mount [WORKSP…'
          to be 'Usage: relayfile mount [WORKSPACE] [L…'

Give the baseline spawn the same RELAYFILE_PROGRAM_NAME the surface sets, so
the comparison isolates routing again. The surface test that asserted the
top-level banner now expects the mounted name, which makes it a stronger
check: it proves both that a leading flag reaches the binary and that the
program name arrived with it.

Not fixed here, and not caused by this branch: client.test.ts's "ErrorEvent
is undefined (Node)" fails identically on origin/main, verified in a clean
worktree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Session-Id: d458bd97-53d8-4f02-be9c-48b67b93c916
@AgentRelayBot
AgentRelayBot merged commit 0506316 into main Sep 19, 2026
12 checks passed
@AgentRelayBot
AgentRelayBot deleted the fix/mounted-program-name branch September 19, 2026 04:03
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.

Mounted agent-relay file tells users to run relayfile, a binary they may not have

1 participant