Running agent-relay node up in a directory with no pinned workspace key silently creates a brand-new workspace — no prompt, no log line distinguishing "minted" from "joined" — even when the signed-in account already has an active workspace. It should join the account's active workspace or require an explicit choice.
Behavior today
- The mint:
crates/broker/src/relaycast/auth.rs:461-464 — when no key candidates resolve, the broker calls create_workspace() unconditionally. - Fresh directories always mint:
deterministic_workspace_name() (auth.rs:258-270) is sha256("{USER}:{cwd}")[..8], so the cwd is in the hash — a fresh directory (or a second clone of the same repo at a different path) always yields a never-seen name and always mints. - The minted workspace isn't bound to the account: the
POST /v1/workspaces call carries no Authorization header. - Root cause on the CLI side:
node up uses a narrower key-resolution chain than other commands. resumePinnedProjectWorkspace (packages/cli/src/cli/lib/broker-lifecycle.ts:1271-1290) checks flag → env → RELAY_NODE_TOKEN → project file, then gives up — it never consults the machine-global store ~/.agentworkforce/relay/workspaces.json (the SDK-backed path in packages/cloud/src/project-workspace-key.ts:109-128 does). - Silent: no stdin read anywhere in the chain;
create_workspace emits no tracing line on success; broker stderr only reaches the user under --verbose. The only signal is the post-hoc Workspace Key: print, identical for minted and joined. - The 409 name-conflict handler actively avoids joining:
auth.rs:659-671 appends a random UUID suffix and mints anyway. - Enrolled nodes mint too: the fleet-enrollment path (
packages/cli/src/cli/commands/node.ts:91-109) sets RELAY_NODE_TOKEN but no workspace key, so an enrolled node — whose enrollment record carries a relayWorkspaceId — still mints a fresh workspace. - A second mint site re-mints when an env-provided key is rejected 401/403/429 and wasn't an explicit join (
auth.rs:538-562).
Expected
Join the account's active workspace when one exists, or stop and require an explicit choice (--workspace-key / interactive confirm on a TTY). Minting should be an explicit act, never a silent default.
Fix seams
lookup_workspace(name) → GET /v1/workspaces/by-name/{name} already exists in the relaycast crate and is never called from crates/broker/src — the natural join-instead-of-mint hook.- Consult the machine-global workspace store in the
node up resolution chain. - No workspace-listing capability exists anywhere in
packages/cloud/packages/sdk/crates (workspace list reads only the local store) — an account-level list would let the CLI offer a real choice. - A prompt has to be hoisted into
runNodeUp/runUpCommand before startBrokerWithPortFallback and before the --background fork (broker-lifecycle.ts:1310, which detaches with stdio: 'ignore') — the decision currently happens inside the Rust broker child where no TTY interaction is possible.
🤖 Generated with Claude Code
Running
agent-relay node upin a directory with no pinned workspace key silently creates a brand-new workspace — no prompt, no log line distinguishing "minted" from "joined" — even when the signed-in account already has an active workspace. It should join the account's active workspace or require an explicit choice.Behavior today
crates/broker/src/relaycast/auth.rs:461-464— when no key candidates resolve, the broker callscreate_workspace()unconditionally.deterministic_workspace_name()(auth.rs:258-270) issha256("{USER}:{cwd}")[..8], so the cwd is in the hash — a fresh directory (or a second clone of the same repo at a different path) always yields a never-seen name and always mints.POST /v1/workspacescall carries noAuthorizationheader.node upuses a narrower key-resolution chain than other commands.resumePinnedProjectWorkspace(packages/cli/src/cli/lib/broker-lifecycle.ts:1271-1290) checks flag → env →RELAY_NODE_TOKEN→ project file, then gives up — it never consults the machine-global store~/.agentworkforce/relay/workspaces.json(the SDK-backed path inpackages/cloud/src/project-workspace-key.ts:109-128does).create_workspaceemits no tracing line on success; broker stderr only reaches the user under--verbose. The only signal is the post-hocWorkspace Key:print, identical for minted and joined.auth.rs:659-671appends a random UUID suffix and mints anyway.packages/cli/src/cli/commands/node.ts:91-109) setsRELAY_NODE_TOKENbut no workspace key, so an enrolled node — whose enrollment record carries arelayWorkspaceId— still mints a fresh workspace.auth.rs:538-562).Expected
Join the account's active workspace when one exists, or stop and require an explicit choice (
--workspace-key/ interactive confirm on a TTY). Minting should be an explicit act, never a silent default.Fix seams
lookup_workspace(name)→GET /v1/workspaces/by-name/{name}already exists in the relaycast crate and is never called fromcrates/broker/src— the natural join-instead-of-mint hook.node upresolution chain.packages/cloud/packages/sdk/crates(workspace listreads only the local store) — an account-level list would let the CLI offer a real choice.runNodeUp/runUpCommandbeforestartBrokerWithPortFallbackand before the--backgroundfork (broker-lifecycle.ts:1310, which detaches withstdio: 'ignore') — the decision currently happens inside the Rust broker child where no TTY interaction is possible.🤖 Generated with Claude Code