agent-relay 3.1.23 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +2 -0
  2. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  3. package/bin/agent-relay-broker-darwin-x64 +0 -0
  4. package/bin/agent-relay-broker-linux-arm64 +0 -0
  5. package/bin/agent-relay-broker-linux-x64 +0 -0
  6. package/dist/index.cjs +4053 -16716
  7. package/dist/src/cli/commands/setup.js +1 -1
  8. package/dist/src/cli/commands/setup.js.map +1 -1
  9. package/dist/src/cli/lib/broker-lifecycle.d.ts.map +1 -1
  10. package/dist/src/cli/lib/broker-lifecycle.js +11 -0
  11. package/dist/src/cli/lib/broker-lifecycle.js.map +1 -1
  12. package/dist/src/cli/lib/relaycast-mcp-command.d.ts +5 -0
  13. package/dist/src/cli/lib/relaycast-mcp-command.d.ts.map +1 -0
  14. package/dist/src/cli/lib/relaycast-mcp-command.js +13 -0
  15. package/dist/src/cli/lib/relaycast-mcp-command.js.map +1 -0
  16. package/dist/src/cli/relaycast-mcp.d.ts +39 -0
  17. package/dist/src/cli/relaycast-mcp.d.ts.map +1 -0
  18. package/dist/src/cli/relaycast-mcp.js +432 -0
  19. package/dist/src/cli/relaycast-mcp.js.map +1 -0
  20. package/package.json +9 -8
  21. package/packages/acp-bridge/package.json +2 -2
  22. package/packages/config/package.json +1 -1
  23. package/packages/hooks/package.json +4 -4
  24. package/packages/memory/package.json +2 -2
  25. package/packages/openclaw/README.md +7 -7
  26. package/packages/openclaw/dist/identity/files.js +5 -5
  27. package/packages/openclaw/dist/identity/files.js.map +1 -1
  28. package/packages/openclaw/dist/setup.js +4 -4
  29. package/packages/openclaw/package.json +2 -2
  30. package/packages/openclaw/skill/SKILL.md +24 -24
  31. package/packages/openclaw/src/identity/files.ts +5 -5
  32. package/packages/openclaw/src/setup.ts +4 -4
  33. package/packages/openclaw/templates/SOUL.md.template +5 -5
  34. package/packages/policy/package.json +2 -2
  35. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts +14 -0
  36. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts.map +1 -0
  37. package/packages/sdk/dist/__tests__/completion-pipeline.test.js +1476 -0
  38. package/packages/sdk/dist/__tests__/completion-pipeline.test.js.map +1 -0
  39. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js +2 -2
  40. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js.map +1 -1
  41. package/packages/sdk/dist/__tests__/unit.test.js +8 -0
  42. package/packages/sdk/dist/__tests__/unit.test.js.map +1 -1
  43. package/packages/sdk/dist/client.js +2 -2
  44. package/packages/sdk/dist/client.js.map +1 -1
  45. package/packages/sdk/dist/examples/example.js +1 -1
  46. package/packages/sdk/dist/examples/example.js.map +1 -1
  47. package/packages/sdk/dist/examples/ralph-loop.js +6 -6
  48. package/packages/sdk/dist/examples/ralph-loop.js.map +1 -1
  49. package/packages/sdk/dist/relay-adapter.js +4 -4
  50. package/packages/sdk/dist/relay-adapter.js.map +1 -1
  51. package/packages/sdk/dist/relay.d.ts +1 -0
  52. package/packages/sdk/dist/relay.d.ts.map +1 -1
  53. package/packages/sdk/dist/relay.js +2 -0
  54. package/packages/sdk/dist/relay.js.map +1 -1
  55. package/packages/sdk/dist/workflows/runner.d.ts +53 -2
  56. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  57. package/packages/sdk/dist/workflows/runner.js +1277 -94
  58. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  59. package/packages/sdk/dist/workflows/trajectory.d.ts +6 -2
  60. package/packages/sdk/dist/workflows/trajectory.d.ts.map +1 -1
  61. package/packages/sdk/dist/workflows/trajectory.js +37 -2
  62. package/packages/sdk/dist/workflows/trajectory.js.map +1 -1
  63. package/packages/sdk/dist/workflows/types.d.ts +88 -0
  64. package/packages/sdk/dist/workflows/types.d.ts.map +1 -1
  65. package/packages/sdk/dist/workflows/types.js.map +1 -1
  66. package/packages/sdk/dist/workflows/validator.js +4 -4
  67. package/packages/sdk/dist/workflows/validator.js.map +1 -1
  68. package/packages/sdk/package.json +2 -2
  69. package/packages/sdk/src/__tests__/completion-pipeline.test.ts +1820 -0
  70. package/packages/sdk/src/__tests__/e2e-owner-review.test.ts +2 -2
  71. package/packages/sdk/src/__tests__/idle-nudge.test.ts +68 -0
  72. package/packages/sdk/src/__tests__/unit.test.ts +10 -0
  73. package/packages/sdk/src/__tests__/workflow-runner.test.ts +113 -4
  74. package/packages/sdk/src/client.ts +2 -2
  75. package/packages/sdk/src/examples/example.ts +1 -1
  76. package/packages/sdk/src/examples/ralph-loop.ts +6 -6
  77. package/packages/sdk/src/relay-adapter.ts +4 -4
  78. package/packages/sdk/src/relay.ts +2 -0
  79. package/packages/sdk/src/workflows/README.md +43 -11
  80. package/packages/sdk/src/workflows/runner.ts +1759 -102
  81. package/packages/sdk/src/workflows/schema.json +6 -0
  82. package/packages/sdk/src/workflows/trajectory.ts +52 -3
  83. package/packages/sdk/src/workflows/types.ts +149 -0
  84. package/packages/sdk/src/workflows/validator.ts +4 -4
  85. package/packages/sdk-py/pyproject.toml +1 -1
  86. package/packages/sdk-py/src/agent_relay/models.py +11 -0
  87. package/packages/sdk-py/src/agent_relay/relay.py +9 -6
  88. package/packages/sdk-py/tests/test_relay_lifecycle_hooks.py +23 -0
  89. package/packages/telemetry/package.json +1 -1
  90. package/packages/trajectory/package.json +2 -2
  91. package/packages/user-directory/package.json +2 -2
  92. package/packages/utils/package.json +2 -2
  93. package/relay-snippets/agent-relay-protocol.md +4 -4
  94. package/relay-snippets/agent-relay-snippet.md +31 -43
@@ -126,6 +126,12 @@ Added workdir to WorktreeWorkflowStep
126
126
  },
127
127
  "idleNudge": {
128
128
  "$ref": "#/definitions/IdleNudgeConfig"
129
+ },
130
+ "completionGracePeriodMs": {
131
+ "type": "integer",
132
+ "minimum": 0,
133
+ "default": 5000,
134
+ "description": "Grace period (ms) after an agent exits with code 0 but without posting the expected coordination signal. During this window the runner checks verification gates and evidence before failing. Set to 0 to disable."
129
135
  }
130
136
  }
131
137
  },
@@ -16,7 +16,7 @@ import { existsSync } from 'node:fs';
16
16
  import { mkdir, writeFile, rename } from 'node:fs/promises';
17
17
  import path from 'node:path';
18
18
 
19
- import type { TrajectoryConfig, WorkflowStep } from './types.js';
19
+ import type { StepCompletionDecision, TrajectoryConfig, WorkflowStep } from './types.js';
20
20
 
21
21
  // ── Trajectory file format (compatible with trail CLI) ───────────────────────
22
22
 
@@ -84,6 +84,8 @@ export interface StepOutcome {
84
84
  nonInteractive?: boolean;
85
85
  /** Duration in ms. */
86
86
  durationMs?: number;
87
+ /** How the step completion was determined. */
88
+ completionMode?: StepCompletionDecision['mode'];
87
89
  }
88
90
 
89
91
  // ── Failure root-cause categories ───────────────────────────────────────────
@@ -339,8 +341,35 @@ export class WorkflowTrajectory {
339
341
  await this.flush();
340
342
  }
341
343
 
344
+ async stepCompletionDecision(stepName: string, decision: StepCompletionDecision): Promise<void> {
345
+ if (!this.enabled || !this.trajectory) return;
346
+
347
+ const modeLabel = decision.mode === 'marker' ? 'marker-based' : `${decision.mode}-based`;
348
+ const reason = decision.reason ? ` — ${decision.reason}` : '';
349
+ const evidence = this.formatCompletionEvidenceSummary(decision.evidence);
350
+ const evidenceSuffix = evidence ? ` (${evidence})` : '';
351
+
352
+ this.addEvent(
353
+ decision.mode === 'marker' ? 'completion-marker' : 'completion-evidence',
354
+ `"${stepName}" ${modeLabel} completion${reason}${evidenceSuffix}`,
355
+ 'medium',
356
+ {
357
+ stepName,
358
+ completionMode: decision.mode,
359
+ reason: decision.reason,
360
+ evidence: decision.evidence,
361
+ }
362
+ );
363
+ await this.flush();
364
+ }
365
+
342
366
  /** Record step completed — captures what was accomplished. */
343
- async stepCompleted(step: WorkflowStep, output: string, attempt: number): Promise<void> {
367
+ async stepCompleted(
368
+ step: WorkflowStep,
369
+ output: string,
370
+ attempt: number,
371
+ decision?: StepCompletionDecision
372
+ ): Promise<void> {
344
373
  if (!this.enabled || !this.trajectory) return;
345
374
 
346
375
  const suffix = attempt > 1 ? ` (after ${attempt} attempts)` : '';
@@ -357,7 +386,12 @@ export class WorkflowTrajectory {
357
386
  ? lastMeaningful
358
387
  : output.trim().slice(0, 120) || '(no output)';
359
388
 
360
- this.addEvent('finding', `"${step.name}" completed${suffix} → ${completion}`, 'medium');
389
+ if (decision) {
390
+ await this.stepCompletionDecision(step.name, decision);
391
+ }
392
+
393
+ const modeSuffix = decision ? ` [${decision.mode}]` : '';
394
+ this.addEvent('finding', `"${step.name}" completed${suffix}${modeSuffix} → ${completion}`, 'medium');
361
395
  await this.flush();
362
396
  }
363
397
 
@@ -697,6 +731,21 @@ export class WorkflowTrajectory {
697
731
  chapter.events.push(event);
698
732
  }
699
733
 
734
+ private formatCompletionEvidenceSummary(
735
+ evidence: StepCompletionDecision['evidence'] | undefined
736
+ ): string | undefined {
737
+ if (!evidence) return undefined;
738
+
739
+ const parts: string[] = [];
740
+ if (evidence.summary) parts.push(evidence.summary);
741
+ if (evidence.signals?.length) parts.push(`signals=${evidence.signals.join(', ')}`);
742
+ if (evidence.channelPosts?.length) parts.push(`channel=${evidence.channelPosts.join(' | ')}`);
743
+ if (evidence.files?.length) parts.push(`files=${evidence.files.join(', ')}`);
744
+ if (evidence.exitCode !== undefined) parts.push(`exit=${evidence.exitCode}`);
745
+
746
+ return parts.length > 0 ? parts.join('; ') : undefined;
747
+ }
748
+
700
749
  private async flush(): Promise<void> {
701
750
  if (!this.trajectory) return;
702
751
 
@@ -76,6 +76,13 @@ export interface SwarmConfig {
76
76
  channel?: string;
77
77
  /** Idle agent detection and nudging configuration for interactive agents. */
78
78
  idleNudge?: IdleNudgeConfig;
79
+ /**
80
+ * Grace period (ms) after an agent exits with code 0 but without posting
81
+ * the expected coordination signal. During this window the runner checks
82
+ * verification gates and evidence before failing the step.
83
+ * Default: 5000 (5 seconds). Set to 0 to disable.
84
+ */
85
+ completionGracePeriodMs?: number;
79
86
  }
80
87
 
81
88
  export type SwarmPattern =
@@ -310,6 +317,128 @@ export interface VerificationCheck {
310
317
  description?: string;
311
318
  }
312
319
 
320
+ // ── Completion evidence ─────────────────────────────────────────────────────
321
+
322
+ export type CompletionEvidenceSignalSource =
323
+ | 'channel'
324
+ | 'stdout'
325
+ | 'stderr'
326
+ | 'process'
327
+ | 'filesystem'
328
+ | 'tool'
329
+ | 'verification';
330
+
331
+ export type CompletionEvidenceSignalKind =
332
+ | 'worker_done'
333
+ | 'lead_done'
334
+ | 'step_complete'
335
+ | 'owner_decision'
336
+ | 'review_decision'
337
+ | 'task_summary'
338
+ | 'verification_passed'
339
+ | 'verification_failed'
340
+ | 'process_exit'
341
+ | 'custom';
342
+
343
+ export interface CompletionEvidenceSignal {
344
+ kind: CompletionEvidenceSignalKind;
345
+ source: CompletionEvidenceSignalSource;
346
+ text: string;
347
+ observedAt: string;
348
+ sender?: string;
349
+ actor?: string;
350
+ role?: string;
351
+ value?: string;
352
+ }
353
+
354
+ export type CompletionEvidenceChannelOrigin = 'runner_post' | 'forwarded_chunk' | 'relay_message';
355
+
356
+ export interface CompletionEvidenceChannelPost {
357
+ stepName: string;
358
+ text: string;
359
+ postedAt: string;
360
+ origin: CompletionEvidenceChannelOrigin;
361
+ completionRelevant: boolean;
362
+ sender?: string;
363
+ actor?: string;
364
+ role?: string;
365
+ target?: string;
366
+ signals: CompletionEvidenceSignal[];
367
+ }
368
+
369
+ export type CompletionEvidenceFileChangeKind = 'created' | 'modified' | 'deleted';
370
+
371
+ export interface CompletionEvidenceFileChange {
372
+ path: string;
373
+ kind: CompletionEvidenceFileChangeKind;
374
+ observedAt: string;
375
+ root?: string;
376
+ }
377
+
378
+ export type CompletionEvidenceToolSideEffectType =
379
+ | 'persist_step_output'
380
+ | 'post_channel_message'
381
+ | 'verification_observed'
382
+ | 'worktree_created'
383
+ | 'owner_monitoring'
384
+ | 'review_started'
385
+ | 'review_completed'
386
+ | 'worker_exit'
387
+ | 'worker_error'
388
+ | 'retry'
389
+ | 'custom';
390
+
391
+ export interface CompletionEvidenceToolSideEffect {
392
+ type: CompletionEvidenceToolSideEffectType;
393
+ detail: string;
394
+ observedAt: string;
395
+ raw?: Record<string, unknown>;
396
+ }
397
+
398
+ export interface StepCompletionEvidence {
399
+ stepName: string;
400
+ status?: WorkflowStepStatus;
401
+ startedAt?: string;
402
+ completedAt?: string;
403
+ lastUpdatedAt: string;
404
+ roots: string[];
405
+ output: {
406
+ stdout: string;
407
+ stderr: string;
408
+ combined: string;
409
+ };
410
+ channelPosts: CompletionEvidenceChannelPost[];
411
+ files: CompletionEvidenceFileChange[];
412
+ process: {
413
+ exitCode?: number;
414
+ exitSignal?: string;
415
+ };
416
+ toolSideEffects: CompletionEvidenceToolSideEffect[];
417
+ coordinationSignals: CompletionEvidenceSignal[];
418
+ }
419
+
420
+ export type StepCompletionMode =
421
+ | 'marker'
422
+ | 'evidence'
423
+ | 'verification'
424
+ | 'owner_decision'
425
+ | 'review'
426
+ | 'heuristic';
427
+
428
+ export interface StepCompletionDecisionEvidence {
429
+ summary?: string;
430
+ signals?: string[];
431
+ channelPosts?: string[];
432
+ files?: string[];
433
+ exitCode?: number;
434
+ }
435
+
436
+ export interface StepCompletionDecision {
437
+ mode: StepCompletionMode;
438
+ reason?: string;
439
+ evidence?: StepCompletionDecisionEvidence;
440
+ }
441
+
313
442
  // ── Coordination ────────────────────────────────────────────────────────────
314
443
 
315
444
  /** Coordination settings for multi-agent synchronization. */
@@ -394,6 +523,25 @@ export interface WorkflowRunRow {
394
523
  }
395
524
 
396
525
  export type WorkflowStepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
526
+ export type WorkflowOwnerDecision =
527
+ | 'COMPLETE'
528
+ | 'INCOMPLETE_RETRY'
529
+ | 'INCOMPLETE_FAIL'
530
+ | 'NEEDS_CLARIFICATION';
531
+ /**
532
+ * Completion reasons are recorded for both successful and failed steps.
533
+ * `retry_requested_by_owner` is a retry-control signal, not a success state:
534
+ * the runner retries while budget remains and fails the step once retries are exhausted.
535
+ */
536
+ export type WorkflowStepCompletionReason =
537
+ | 'completed_verified'
538
+ | 'completed_by_owner_decision'
539
+ | 'completed_by_evidence'
540
+ | 'completed_by_process_exit'
541
+ | 'retry_requested_by_owner'
542
+ | 'failed_verification'
543
+ | 'failed_owner_decision'
544
+ | 'failed_no_evidence';
397
545
 
398
546
  /** Database row representing a single workflow step execution. */
399
547
  export interface WorkflowStepRow {
@@ -410,6 +558,7 @@ export interface WorkflowStepRow {
410
558
  dependsOn: string[];
411
559
  output?: string;
412
560
  error?: string;
561
+ completionReason?: WorkflowStepCompletionReason;
413
562
  startedAt?: string;
414
563
  completedAt?: string;
415
564
  retryCount: number;
@@ -90,22 +90,22 @@ export function validateWorkflow(config: RelayYamlConfig): ValidationIssue[] {
90
90
  task.length > 500 &&
91
91
  !task.includes('do not') &&
92
92
  !task.includes('Do NOT') &&
93
- !task.includes('relay_spawn') &&
93
+ !task.includes('mcp__relaycast__agent_add') &&
94
94
  !task.includes('add_agent')
95
95
  ) {
96
96
  issues.push({
97
97
  severity: 'info',
98
98
  code: 'CLAUDE_NO_SPAWN_GUARD',
99
99
  message: `Step "${step.name}" uses interactive claude with a long task. Claude may spontaneously spawn sub-agents via relay MCP tools.`,
100
- fix: `Add "Do NOT use relay_spawn or add_agent to spawn sub-agents." to the task, or use \`interactive: false\`.`,
100
+ fix: `Add "Do NOT use mcp__relaycast__agent_add or add_agent to spawn sub-agents." to the task, or use \`interactive: false\`.`,
101
101
  location: `step:${step.name}`,
102
102
  });
103
103
  }
104
104
 
105
- // Check 4: non-interactive agent that references relay_send in task
105
+ // Check 4: non-interactive agent that references relay messaging tools in task
106
106
  if (
107
107
  def.interactive === false &&
108
- (task.includes('relay_send') || task.includes('post_message') || task.includes('check_inbox'))
108
+ (task.includes('mcp__relaycast__dm_send') || task.includes('mcp__relaycast__message_post') || task.includes('mcp__relaycast__inbox_check'))
109
109
  ) {
110
110
  issues.push({
111
111
  severity: 'warning',
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agent-relay-sdk"
7
- version = "3.1.23"
7
+ version = "3.2.1"
8
8
  description = "Python SDK for Agent Relay workflows"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -25,3 +25,14 @@ class Models:
25
25
  GEMINI_2_5_PRO = "gemini-2.5-pro"
26
26
  GEMINI_2_5_FLASH = "gemini-2.5-flash"
27
27
  GEMINI_2_5_FLASH_LITE = "gemini-2.5-flash-lite"
28
+
29
+ class Opencode:
30
+ OPENCODE_BIG_PICKLE = "opencode/big-pickle"
31
+ OPENCODE_GPT_5_NANO = "opencode/gpt-5-nano"
32
+ OPENCODE_MIMO_V2_FLASH_FREE = "opencode/mimo-v2-flash-free"
33
+ OPENCODE_MINIMAX_M2_5_FREE = "opencode/minimax-m2.5-free"
34
+ OPENAI_CODEX_MINI_LATEST = "openai/codex-mini-latest"
35
+ OPENAI_GPT_5_2 = "openai/gpt-5.2"
36
+ OPENAI_O3_MINI = "openai/o3-mini"
37
+ OPENAI_O3_PRO = "openai/o3-pro"
38
+ OPENAI_O4_MINI = "openai/o4-mini"
@@ -291,10 +291,11 @@ class HumanHandle:
291
291
  class AgentSpawner:
292
292
  """Shorthand spawner for a specific CLI (e.g., relay.claude.spawn(...))."""
293
293
 
294
- def __init__(self, cli: str, default_name: str, relay: AgentRelay):
294
+ def __init__(self, cli: str, default_name: str, relay: AgentRelay, transport: str = "pty"):
295
295
  self._cli = cli
296
296
  self._default_name = default_name
297
297
  self._relay = relay
298
+ self._transport = transport
298
299
 
299
300
  async def spawn(
300
301
  self,
@@ -326,9 +327,10 @@ class AgentSpawner:
326
327
  )
327
328
 
328
329
  try:
329
- result = await client.spawn_pty(
330
+ result = await client.spawn_provider(
330
331
  name=agent_name,
331
- cli=self._cli,
332
+ provider=self._cli,
333
+ transport=self._transport,
332
334
  args=args or [],
333
335
  channels=agent_channels,
334
336
  task=task,
@@ -434,9 +436,10 @@ class AgentRelay:
434
436
  self._idle_resolvers: dict[str, list[asyncio.Future[str]]] = {}
435
437
 
436
438
  # Shorthand spawners
437
- self.codex = AgentSpawner("codex", "Codex", self)
438
- self.claude = AgentSpawner("claude", "Claude", self)
439
- self.gemini = AgentSpawner("gemini", "Gemini", self)
439
+ self.codex = AgentSpawner("codex", "Codex", self, transport="pty")
440
+ self.claude = AgentSpawner("claude", "Claude", self, transport="pty")
441
+ self.gemini = AgentSpawner("gemini", "Gemini", self, transport="pty")
442
+ self.opencode = AgentSpawner("opencode", "OpenCode", self, transport="headless")
440
443
 
441
444
  @property
442
445
  def workspace_key(self) -> Optional[str]:
@@ -23,6 +23,12 @@ class _FakeRelayClient:
23
23
  raise self.spawn_error
24
24
  return {"name": kwargs["name"], "runtime": "pty"}
25
25
 
26
+ async def spawn_provider(self, **kwargs):
27
+ self.spawn_calls.append(kwargs)
28
+ if self.spawn_error:
29
+ raise self.spawn_error
30
+ return {"name": kwargs["name"], "runtime": "pty"}
31
+
26
32
  async def release(self, name: str, reason: str | None = None):
27
33
  self.release_calls.append((name, reason))
28
34
  if self.release_error:
@@ -142,6 +148,23 @@ async def test_shorthand_spawn_lifecycle_hooks_success():
142
148
 
143
149
  assert agent.name == "ShorthandWorker"
144
150
  assert events == ["start", "success"]
151
+ assert client.spawn_calls[-1]["transport"] == "pty"
152
+
153
+
154
+ @pytest.mark.asyncio
155
+ async def test_opencode_shorthand_spawn_success():
156
+ relay = AgentRelay()
157
+ client = _FakeRelayClient()
158
+ relay._ensure_started = AsyncMock(return_value=client)
159
+
160
+ agent = await relay.opencode.spawn(
161
+ name="OpencodeWorker",
162
+ channels=["general"],
163
+ )
164
+
165
+ assert agent.name == "OpencodeWorker"
166
+ assert client.spawn_calls[-1]["provider"] == "opencode"
167
+ assert client.spawn_calls[-1]["transport"] == "headless"
145
168
 
146
169
 
147
170
  @pytest.mark.asyncio
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/telemetry",
3
- "version": "3.1.23",
3
+ "version": "3.2.1",
4
4
  "description": "Anonymous telemetry for Agent Relay usage analytics",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/trajectory",
3
- "version": "3.1.23",
3
+ "version": "3.2.1",
4
4
  "description": "Trajectory integration utilities (trail/PDERO) for Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/config": "3.1.23"
25
+ "@agent-relay/config": "3.2.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/user-directory",
3
- "version": "3.1.23",
3
+ "version": "3.2.1",
4
4
  "description": "User directory service for agent-relay (per-user credential storage)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/utils": "3.1.23"
25
+ "@agent-relay/utils": "3.2.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.19.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/utils",
3
- "version": "3.1.23",
3
+ "version": "3.2.1",
4
4
  "description": "Shared utilities for agent-relay: logging, name generation, command resolution, update checking",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.js",
@@ -112,7 +112,7 @@
112
112
  "vitest": "^3.2.4"
113
113
  },
114
114
  "dependencies": {
115
- "@agent-relay/config": "3.1.23",
115
+ "@agent-relay/config": "3.2.1",
116
116
  "compare-versions": "^6.1.1"
117
117
  },
118
118
  "publishConfig": {
@@ -4,10 +4,10 @@ Advanced features for session continuity and trajectory tracking.
4
4
 
5
5
  ## Session Continuity
6
6
 
7
- Use `relay_send` with a continuity message to save state for session recovery:
7
+ Use `mcp__relaycast__send_dm` with a continuity message to save state for session recovery:
8
8
 
9
9
  ```
10
- relay_send(to: "system", message: "KIND: continuity\nACTION: save\n\nCurrent task: Implementing user authentication\nCompleted: User model, JWT utils\nIn progress: Login endpoint")
10
+ mcp__relaycast__send_dm(to: "system", text: "KIND: continuity\nACTION: save\n\nCurrent task: Implementing user authentication\nCompleted: User model, JWT utils\nIn progress: Login endpoint")
11
11
  ```
12
12
 
13
13
  ### When to Save
@@ -51,10 +51,10 @@ trail abandon --reason "Blocked by missing credentials"
51
51
 
52
52
  ## Cross-Project Messaging
53
53
 
54
- In bridge mode, use `project:agent` format with `relay_send`:
54
+ In bridge mode, use `project:agent` format with `mcp__relaycast__send_dm`:
55
55
 
56
56
  ```
57
- relay_send(to: "frontend:Designer", message: "Please update the login UI.")
57
+ mcp__relaycast__send_dm(to: "frontend:Designer", text: "Please update the login UI.")
58
58
  ```
59
59
 
60
60
  Special targets:
@@ -4,41 +4,30 @@ Real-time agent-to-agent messaging via MCP tools.
4
4
 
5
5
  ## MCP Tools
6
6
 
7
- All agent communication uses MCP tools provided by the Relaycast MCP server:
8
-
9
- | Tool | Description |
10
- | ------------------------------ | ------------------------------------- |
11
- | `relay_send(to, message)` | Send a message to an agent or channel |
12
- | `relay_inbox()` | Check your inbox for new messages |
13
- | `relay_who()` | List online agents |
14
- | `relay_spawn(name, cli, task)` | Spawn a new worker agent |
15
- | `relay_release(name)` | Release/stop a worker agent |
16
- | `relay_status()` | Check relay connection status |
7
+ All agent communication uses MCP tools provided by the Relaycast MCP server.
8
+ Tool names use dot-notation: Claude uses `mcp__relaycast__<category>_<action>`, other CLIs use `relaycast.<category>.<action>`.
9
+
10
+ | Tool | Description |
11
+ | --------------------------------- | ------------------------------------- |
12
+ | `dm_send(to, text)` | Send a DM to an agent |
13
+ | `message_post(channel, text)` | Post a message to a channel |
14
+ | `inbox_check()` | Check your inbox for new messages |
15
+ | `agent_list()` | List online agents |
16
+ | `agent_add(name, cli, task)` | Spawn a new worker agent |
17
+ | `agent_remove(name)` | Release/stop a worker agent |
17
18
 
18
19
  ## Sending Messages
19
20
 
20
- Use the `relay_send` MCP tool:
21
-
22
- ```
23
- relay_send(to: "AgentName", message: "Your message here")
24
- ```
25
-
26
21
  ### Direct Messages
27
22
 
28
23
  ```
29
- relay_send(to: "Bob", message: "Can you review my code changes?")
30
- ```
31
-
32
- ### Broadcast to All
33
-
34
- ```
35
- relay_send(to: "*", message: "I've finished the auth module")
24
+ mcp__relaycast__dm_send(to: "Bob", text: "Can you review my code changes?")
36
25
  ```
37
26
 
38
27
  ### Channel Messages
39
28
 
40
29
  ```
41
- relay_send(to: "#frontend", message: "The API endpoints are ready")
30
+ mcp__relaycast__message_post(channel: "general", text: "The API endpoints are ready")
42
31
  ```
43
32
 
44
33
  ## Spawning & Releasing Agents
@@ -46,23 +35,24 @@ relay_send(to: "#frontend", message: "The API endpoints are ready")
46
35
  ### Spawn a Worker
47
36
 
48
37
  ```
49
- relay_spawn(name: "WorkerName", cli: "claude", task: "Task description here")
38
+ mcp__relaycast__agent_add(name: "WorkerName", cli: "claude", task: "Task description here")
50
39
  ```
51
40
 
52
41
  ### CLI Options
53
42
 
54
- | CLI Value | Description |
55
- | --------- | ----------------------- |
56
- | `claude` | Claude Code (Anthropic) |
57
- | `codex` | Codex CLI (OpenAI) |
58
- | `gemini` | Gemini CLI (Google) |
59
- | `aider` | Aider coding assistant |
60
- | `goose` | Goose AI assistant |
43
+ | CLI Value | Description |
44
+ | ----------- | ---------------------------- |
45
+ | `claude` | Claude Code (Anthropic) |
46
+ | `codex` | Codex CLI (OpenAI) |
47
+ | `gemini` | Gemini CLI (Google) |
48
+ | `opencode` | OpenCode CLI (multi-model) |
49
+ | `aider` | Aider coding assistant |
50
+ | `goose` | Goose AI assistant |
61
51
 
62
52
  ### Release a Worker
63
53
 
64
54
  ```
65
- relay_release(name: "WorkerName")
55
+ mcp__relaycast__agent_remove(name: "WorkerName")
66
56
  ```
67
57
 
68
58
  ## Receiving Messages
@@ -86,11 +76,11 @@ Reply to the channel shown, not the sender.
86
76
  If you were spawned by another agent:
87
77
 
88
78
  1. Your first message is your task from your spawner
89
- 2. Use `relay_send` to reply to your spawner
79
+ 2. Use `mcp__relaycast__dm_send` to reply to your spawner
90
80
  3. Report status to your spawner (your lead), not broadcast
91
81
 
92
82
  ```
93
- relay_send(to: "Lead", message: "ACK: Starting on the task.")
83
+ mcp__relaycast__dm_send(to: "Lead", text: "ACK: Starting on the task.")
94
84
  ```
95
85
 
96
86
  ## Protocol
@@ -103,10 +93,10 @@ relay_send(to: "Lead", message: "ACK: Starting on the task.")
103
93
 
104
94
  **Local communication** uses plain agent names. The `project:` prefix is **ONLY** for cross-project bridge mode.
105
95
 
106
- | Context | Correct | Incorrect |
107
- | ---------------------- | ------------------------------------------ | ------------------------------------- |
108
- | Local (same project) | `relay_send(to: "Lead", ...)` | `relay_send(to: "project:lead", ...)` |
109
- | Bridge (cross-project) | `relay_send(to: "frontend:Designer", ...)` | N/A |
96
+ | Context | Correct | Incorrect |
97
+ | ---------------------- | ----------------------------------------------------------- | ------------------------------------------------------ |
98
+ | Local (same project) | `mcp__relaycast__dm_send(to: "Lead", ...)` | `mcp__relaycast__dm_send(to: "project:lead", ...)` |
99
+ | Bridge (cross-project) | `mcp__relaycast__dm_send(to: "frontend:Designer", ...)` | N/A |
110
100
 
111
101
  ## Multi-Workspace
112
102
 
@@ -118,12 +108,10 @@ Relay message from Alice [my-team / abc123]: Hello!
118
108
 
119
109
  - Messages are scoped to the originating workspace
120
110
  - Reply within the same workspace context shown in the message header
121
- - Use `relay_status()` to see which workspaces are connected
122
111
 
123
112
  ## Checking Status
124
113
 
125
114
  ```
126
- relay_who() # List online agents
127
- relay_inbox() # Check for unread messages
128
- relay_status() # Check connection status
115
+ mcp__relaycast__agent_list() # List online agents
116
+ mcp__relaycast__inbox_check() # Check for unread messages
129
117
  ```