feat(persona): wire relaycast MCP into broker-launched personas#170
feat(persona): wire relaycast MCP into broker-launched personas#170khaliqgant wants to merge 1 commit into
Conversation
A persona launched under an Agent Relay broker couldn't message the team: the broker auto-wires the relaycast MCP for harnesses it spawns directly, but a persona's PTY command is the `agentworkforce` launcher (not the harness), and the claude branch emits `--strict-mcp-config`, so any project `.mcp.json` is ignored. The only injection point that survives strict mode is the `--mcp-config` payload itself. - persona-kit/interactive-spec: add an optional `relayMcp` input to `buildInteractiveSpec`. When set, a `relaycast` stdio MCP server (`npx -y @relaycast/mcp` + `RELAY_*` env) is merged into the persona's declared `mcpServers` before the harness switch. A persona-declared `relaycast` still wins. Wired for claude (inside the strict payload) and codex (`--config`); opencode keeps its existing "MCP unsupported" warning. Kept pure — callers pass `relayMcp` explicitly. - cli: resolve `relayMcp` from the `RELAY_*` env the broker sets on the launcher (`RELAY_API_KEY` + the broker-assigned `RELAY_AGENT_NAME`, plus optional base-url / default-workspace) and pass it through at the live-launch and dry-run call sites. No relay env ⇒ undefined ⇒ a plain `agentworkforce agent` run is unaffected. Pairs with a broker change that exposes RELAY_AGENT_NAME to the launcher even when skip_relay_prompt is set (AgentWorkforce/relay). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe PR adds Agent Relay MCP broker support to interactive harness sessions. A new ChangesAgent Relay MCP Integration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add 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. Comment |
There was a problem hiding this comment.
Code Review
This pull request adds support for injecting a relaycast MCP server configuration into the harness's MCP config when a persona is launched under an Agent Relay broker. It resolves the broker's environment variables and merges the relaycast server into the persona's declared servers. Feedback on the changes suggests simplifying the code by replacing conditional object spreading with direct property assignments or passing optional properties directly where applicable.
| return { | ||
| apiKey, | ||
| agentName, | ||
| ...(baseUrl ? { baseUrl } : {}), | ||
| ...(defaultWorkspace ? { defaultWorkspace } : {}) | ||
| }; |
There was a problem hiding this comment.
Instead of using conditional object spreading for optional properties like baseUrl and defaultWorkspace, you can simplify the return object by directly assigning them with a fallback to undefined. Since these properties are optional in RelayMcpConfig, undefined values are perfectly valid and cleaner to read.
| return { | |
| apiKey, | |
| agentName, | |
| ...(baseUrl ? { baseUrl } : {}), | |
| ...(defaultWorkspace ? { defaultWorkspace } : {}) | |
| }; | |
| return { | |
| apiKey, | |
| agentName, | |
| baseUrl: baseUrl || undefined, | |
| defaultWorkspace: defaultWorkspace || undefined | |
| }; |
| systemPrompt, | ||
| harnessSettings, | ||
| mcpServers: mcpResolution.servers, | ||
| ...(relayMcp ? { relayMcp } : {}), |
There was a problem hiding this comment.
| systemPrompt, | ||
| harnessSettings, | ||
| mcpServers: resolvedMcp, | ||
| ...(relayMcp ? { relayMcp } : {}), |
There was a problem hiding this comment.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/cli.ts`:
- Around line 1751-1759: The spawn summary uses resolvedMcp rather than the
final spec (which may include relayMcp), causing relaycast to be omitted from
the sanitized mcp output; update the summary generation to derive the displayed
mcp/relay info from the built spec returned by buildInteractiveSpec (inspect
spec.mcpServers and spec.relayMcp) instead of using resolvedMcp so that injected
relayMcp is shown in the "mcp-strict=" log entry.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 15388f36-f792-4ac8-a36f-d197ecc336f3
📒 Files selected for processing (4)
packages/cli/src/cli.tspackages/persona-kit/src/index.tspackages/persona-kit/src/interactive-spec.test.tspackages/persona-kit/src/interactive-spec.ts
| const relayMcp = resolveRelayMcpFromEnv(process.env); | ||
| const spec = buildInteractiveSpec({ | ||
| harness, | ||
| personaId, | ||
| model, | ||
| systemPrompt, | ||
| harnessSettings, | ||
| mcpServers: resolvedMcp, | ||
| ...(relayMcp ? { relayMcp } : {}), |
There was a problem hiding this comment.
Include injected relaycast in the sanitized spawn summary.
The broker path now injects relaycast into spec, but the later mcp-strict= log still derives from resolvedMcp, so broker launches can print (none) even when relaycast was added successfully. That makes this feature harder to verify and debug.
🩹 Proposed fix
const relayMcp = resolveRelayMcpFromEnv(process.env);
+ const summaryMcpServerNames = Object.keys(
+ relayMcp ? { relaycast: true, ...(resolvedMcp ?? {}) } : (resolvedMcp ?? {})
+ );
const spec = buildInteractiveSpec({
harness,
personaId,
model,
systemPrompt,
@@
const summary: string[] = [`model=${model}`];
if (harness === 'claude') {
- const servers = Object.keys(resolvedMcp ?? {});
- summary.push(`mcp-strict=${servers.length ? servers.join(',') : '(none)'}`);
+ summary.push(
+ `mcp-strict=${summaryMcpServerNames.length ? summaryMcpServerNames.join(',') : '(none)'}`
+ );
if (effectiveSelection.permissions?.allow?.length) {
summary.push(`allow=${effectiveSelection.permissions.allow.length} rule(s)`);
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/cli.ts` around lines 1751 - 1759, The spawn summary uses
resolvedMcp rather than the final spec (which may include relayMcp), causing
relaycast to be omitted from the sanitized mcp output; update the summary
generation to derive the displayed mcp/relay info from the built spec returned
by buildInteractiveSpec (inspect spec.mcpServers and spec.relayMcp) instead of
using resolvedMcp so that injected relayMcp is shown in the "mcp-strict=" log
entry.
There was a problem hiding this comment.
2 issues found across 4 files
You’re at about 92% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/persona-kit/src/interactive-spec.ts">
<violation number="1" location="packages/persona-kit/src/interactive-spec.ts:259">
P3: Relay-injected MCP servers now trigger an opencode warning that incorrectly says the persona declared `mcpServers`, which is misleading for relay-only runs.</violation>
</file>
<file name="packages/cli/src/cli.ts">
<violation number="1" location="packages/cli/src/cli.ts:1382">
P3: The launch summary can become misleading here: relaycast may be injected via `relayMcp`, but `mcp-strict=` still reflects only `resolvedMcp`. Include injected relay MCP servers in the summary calculation so broker-launched runs don't report `(none)` when MCP wiring is actually present.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| // under a broker. A persona-declared `relaycast` wins, so authors can still | ||
| // override it. Kept pure: callers pass relayMcp explicitly (resolved from | ||
| // env), so this function reads no environment itself. | ||
| const mcpServers = input.relayMcp |
There was a problem hiding this comment.
P3: Relay-injected MCP servers now trigger an opencode warning that incorrectly says the persona declared mcpServers, which is misleading for relay-only runs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/persona-kit/src/interactive-spec.ts, line 259:
<comment>Relay-injected MCP servers now trigger an opencode warning that incorrectly says the persona declared `mcpServers`, which is misleading for relay-only runs.</comment>
<file context>
@@ -186,17 +224,41 @@ function appendCodexMcpServerArgs(
+ // under a broker. A persona-declared `relaycast` wins, so authors can still
+ // override it. Kept pure: callers pass relayMcp explicitly (resolved from
+ // env), so this function reads no environment itself.
+ const mcpServers = input.relayMcp
+ ? { relaycast: buildRelaycastMcpServer(input.relayMcp), ...(input.mcpServers ?? {}) }
+ : input.mcpServers;
</file context>
| systemPrompt, | ||
| harnessSettings, | ||
| mcpServers: mcpResolution.servers, | ||
| ...(relayMcp ? { relayMcp } : {}), |
There was a problem hiding this comment.
P3: The launch summary can become misleading here: relaycast may be injected via relayMcp, but mcp-strict= still reflects only resolvedMcp. Include injected relay MCP servers in the summary calculation so broker-launched runs don't report (none) when MCP wiring is actually present.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/cli.ts, line 1382:
<comment>The launch summary can become misleading here: relaycast may be injected via `relayMcp`, but `mcp-strict=` still reflects only `resolvedMcp`. Include injected relay MCP servers in the summary calculation so broker-launched runs don't report `(none)` when MCP wiring is actually present.</comment>
<file context>
@@ -1343,13 +1371,15 @@ function runDryRun(selection: PersonaSelection): number {
systemPrompt,
harnessSettings,
mcpServers: mcpResolution.servers,
+ ...(relayMcp ? { relayMcp } : {}),
permissions: effectiveSelection.permissions
});
</file context>
Why
A persona launched under an Agent Relay broker (e.g. from Pear) couldn't message the team, while a regular broker-spawned agent can. Root cause:
agentworkforcelauncher, not the harness — the real claude is a grandchild the broker never sees, so it skips MCP wiring..mcp.jsoneither: the claude branch emits--strict-mcp-config, so claude only sees the--mcp-configpayload and ignores project/user config.The only injection point that survives strict mode is the
--mcp-configpayload itself — i.e. the persona'smcpServersmap thatbuildInteractiveSpeccompiles. So that's where relaycast has to go.What changed
packages/persona-kit—buildInteractiveSpec:relayMcpinput ({ apiKey, agentName, baseUrl?, defaultWorkspace? }) + exportedRelayMcpConfigtype.relaycaststdio server (npx -y @relaycast/mcp+ theRELAY_*env block, mirroring what the broker injects for a recognized harness) is merged into the persona's declaredmcpServersbefore the harness switch. A persona-declaredrelaycaststill wins, so authors can override.--mcp-configpayload) and codex (--config mcp_servers.relaycast.*). opencode keeps its existing "MCP injection unsupported" warning — unchanged.relayMcpexplicitly.packages/cli:resolveRelayMcpFromEnv(process.env)builds the config from theRELAY_*env the broker sets on the launcher:RELAY_API_KEY+ the broker-assignedRELAY_AGENT_NAME(both required), plus optional base-url / default-workspace. Passed through at the live-launch and dry-run call sites.agentworkforce agentrun.Depends on
AgentWorkforce/relay#1018 — the broker must expose
RELAY_AGENT_NAMEto the launcher even underskip_relay_prompt(persona spawns set it). Without that the agent name is absent andresolveRelayMcpFromEnvreturns undefined (safe no-op), so this PR is harmless to merge independently but only takes effect once the broker change ships.Testing
persona-kit:tsc --noEmitclean; full suite 235 passed (6 new tests covering claude injection, env-omission, persona-override precedence, no-relay baseline, codex--config, opencode warning).cli:tsc --noEmitclean; full suite 210 passed.Not covered (follow-ups)
RELAY_WORKSPACES_JSON) is not threaded through — single-workspace (RELAY_DEFAULT_WORKSPACE) only, which is the common case.🤖 Generated with Claude Code