Uh oh!
There was an error while loading. Please reload this page.
feat: multi-workspace runtime support - #519
Conversation
| let _ = pty.write_all(b" | ||
| "); |
There was a problem hiding this comment.
🔴 Retry injection writes newline+spaces instead of carriage return to PTY
In the retry injection path, the old code pty.write_all(b"\r") (carriage return / Enter key to submit the injected text) was accidentally replaced with a raw multi-line byte string b"\n " (a newline followed by 8 spaces). This means the re-injected message will never be submitted to the CLI — the PTY receives garbage whitespace instead of an Enter keystroke. The original code at src/wrap.rs before this PR used let _ = pty.write_all(b"\r"); which correctly pressed Enter. The non-retry injection path at src/wrap.rs:916 still correctly uses pty.write_all(b"\r"), confirming this was a reformatting accident during the multi-workspace refactor.
| let _ = pty.write_all(b" | |
| "); | |
| let _ = pty.write_all(b"\r"); |
Was this helpful? React with 👍 or 👎 to provide feedback.
The retry re-injection code was sending a literal newline + spaces instead of \r (carriage return) after writing the injection to the PTY. This would cause retry deliveries to fail silently in wrap mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
- BUG-2: Use workspace-specific HTTP client and ws_control_tx for broker spawn/release instead of always using the default workspace's client - P1: Add workspace_id filtering to routing resolution so messages from workspace A's #general don't cross-deliver to workspace B's workers - Add workspace_id to RoutingWorker and WorkerHandle, with backwards compat (None matches all workspaces for legacy/SDK-spawned workers) - Update agent-relay-snippet.md with multi-workspace section - Remove unnecessary #[allow(dead_code)] on DeliveryOutcome::Failed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
The constructor requires all 8 parameters for initialization and does not benefit from a builder pattern at this stage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The dedup key format for incoming WS events was changed to `workspace_id:event_id`, but MCP self-echo pre-seeding still inserted bare message IDs. This mismatch caused duplicate echo messages because the pre-seeded bare ID never matched the scoped incoming key. Pre-seed dedup entries for all workspaces so the scoped keys match on arrival. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…orward workspace env vars in MCP snippets Gap 1: When a configured default_workspace_id is not found in the lookup table, the error now says "workspace_not_found:" instead of "ambiguous_workspace:" (both in relay_send routing and protocol frame handling). The "ambiguous_workspace:" error remains for the fallback case where multiple workspaces exist with no default configured. Gap 2: Forward RELAY_WORKSPACES_JSON and RELAY_DEFAULT_WORKSPACE env vars through MCP configuration snippets for all supported CLIs (claude, codex, gemini/droid, opencode, cursor) so spawned child agents inherit workspace context and can connect to the correct workspaces. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
RELAY_WORKSPACES_JSON contains JSON with inner double quotes that break TOML basic-string parsing in codex --config args. Escape backslashes and quotes before interpolation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
* feat: add multi-workspace auth plumbing * feat: wire multi-workspace runtime flows * chore: record multi-workspace implementation trail * fix: restore carriage return in wrap retry PTY injection The retry re-injection code was sending a literal newline + spaces instead of \r (carriage return) after writing the injection to the PTY. This would cause retry deliveries to fail silently in wrap mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address multi-workspace code review bugs from PR #519 - BUG-2: Use workspace-specific HTTP client and ws_control_tx for broker spawn/release instead of always using the default workspace's client - P1: Add workspace_id filtering to routing resolution so messages from workspace A's #general don't cross-deliver to workspace B's workers - Add workspace_id to RoutingWorker and WorkerHandle, with backwards compat (None matches all workspaces for legacy/SDK-spawned workers) - Update agent-relay-snippet.md with multi-workspace section - Remove unnecessary #[allow(dead_code)] on DeliveryOutcome::Failed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: auto-format Rust code with cargo fmt * fix: allow clippy too_many_arguments on MultiWorkspaceSession::new The constructor requires all 8 parameters for initialization and does not benefit from a builder pattern at this stage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Align SDK send payload with workspace fields * fix: use workspace-scoped dedup keys for MCP self-echo pre-seeding The dedup key format for incoming WS events was changed to `workspace_id:event_id`, but MCP self-echo pre-seeding still inserted bare message IDs. This mismatch caused duplicate echo messages because the pre-seeded bare ID never matched the scoped incoming key. Pre-seed dedup entries for all workspaces so the scoped keys match on arrival. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct error message for default workspace lookup failure and forward workspace env vars in MCP snippets Gap 1: When a configured default_workspace_id is not found in the lookup table, the error now says "workspace_not_found:" instead of "ambiguous_workspace:" (both in relay_send routing and protocol frame handling). The "ambiguous_workspace:" error remains for the fallback case where multiple workspaces exist with no default configured. Gap 2: Forward RELAY_WORKSPACES_JSON and RELAY_DEFAULT_WORKSPACE env vars through MCP configuration snippets for all supported CLIs (claude, codex, gemini/droid, opencode, cursor) so spawned child agents inherit workspace context and can connect to the correct workspaces. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: escape TOML string values for codex --config workspace env vars RELAY_WORKSPACES_JSON contains JSON with inner double quotes that break TOML basic-string parsing in codex --config args. Escape backslashes and quotes before interpolation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
- BUG-2: Use workspace-specific HTTP client and ws_control_tx for broker spawn/release instead of always using the default workspace's client - P1: Add workspace_id filtering to routing resolution so messages from workspace A's #general don't cross-deliver to workspace B's workers - Add workspace_id to RoutingWorker and WorkerHandle, with backwards compat (None matches all workspaces for legacy/SDK-spawned workers) - Update agent-relay-snippet.md with multi-workspace section - Remove unnecessary #[allow(dead_code)] on DeliveryOutcome::Failed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements multi-workspace support for the relay runtime, allowing one agent process to connect to multiple Relaycast workspaces simultaneously.
Changes
Auth & Session Model (~565 lines)
auth.rs:CredentialCache→CredentialSetwithmemberships[]anddefault_workspace_idmulti_workspace.rs:MultiWorkspaceSessionmanaging N WebSocket connections with merged event fan-inRELAY_API_KEYauto-upgrades to single-entry membership setRELAY_WORKSPACES_JSONenv var for multi-workspace bootstrapEvent Routing (~100 lines)
types.rs:workspace_idandworkspace_aliasadded toInboundRelayEvent,BrokerCommandEvent,InjectRequestmessage_bridge.rs: accepts workspace context, emits workspace-scoped eventsrouting.rs: routes by(workspace_id, target)instead of justtargetRuntime Flows (~700 lines)
main.rs: merged receive loop, workspace-aware self-echo filtering, history/replaylisten_api.rs:/api/sendacceptsworkspaceId/workspaceAlias,/api/configreports membershipswrap.rs: workspace-qualified PTY injection when multi-workspace activespawner.rs: passesRELAY_WORKSPACES_JSONandRELAY_DEFAULT_WORKSPACEto child processesBackwards Compatibility
/api/sendwithout workspace valid when single membership or default setCompiles clean (
cargo checkpasses).See SPEC.md on
feature/multi-workspace-supportbranch for full architecture details.