Skip to content

docs: align web/content/docs with actual SDK/CLI implementation#1172

Merged
willwashburn merged 8 commits into
mainfrom
claude/bold-mendel-jpjj0f
Jun 19, 2026
Merged

docs: align web/content/docs with actual SDK/CLI implementation#1172
willwashburn merged 8 commits into
mainfrom
claude/bold-mendel-jpjj0f

Conversation

@willwashburn

@willwashburn willwashburn commented Jun 19, 2026

Copy link
Copy Markdown
Member

Audited all 27 docs in web/content/docs/ against the actual implementation (packages/sdk/src, packages/cli/src, harnesses, harness-driver). Every API name, signature, event, MCP tool, CLI command, and example was verified against source; unverifiable/fictional content was removed.

Cross-cutting correctness bugs

  • Actions registered on the wrong client. Examples registered on the workspace client (relay.registerAction), which agent-relay.ts:256 confirms stays in-process and is never exposed via MCP. Fixed to register on an agent client in quickstart, actions, events, event-handlers, orchestrating-with-actions, agent-relay-mcp, typescript-sdk.
  • envelope.from.handle doesn't existRelayMessageSender is { id?, name? }. Fixed to from?.name throughout.
  • Action-handler agent.handle doesn't exist — the caller is { name, id?, type? }. Fixed to agent.name.
  • claude.create({ relay }) returns a handle, not a messaging client (no sendMessage). Fixed examples to use relay.messages.send({ from }).
  • register is idempotent by default (strict: true to reject), not "rejects existing names." Fixed in workspaces, typescript-sdk, migration.

Type/shape definitions rewritten to match source

  • session-capabilities: real AgentSessionStatus (5 values), corrected AgentSessionEvent union fields (usage, session., message., terminal.screen columns, tool.*).
  • delivery: real DeliveryRunner class + AgentDeliveryAdapter interface (documented deliver/retry/flush don't exist); delivery events as nested session events.
  • harnesses: real HarnessCreateContext/AgentIdentity; normalizeAgentIdentity(ctx.agent) instead of nonexistent ctx.ids.agent(...).
  • events: corrected RelayEvent union, envelope schema, event-name vocabulary (agent.status.idle).

Commands/tools

  • agent-relay-mcp: real tool names (post_message, send_dm, reply_to_thread, add_reaction, check_inbox, mark_message_read); agent-relay mcp has no start/install subcommands; removed nonexistent flush_deliveries/list_events.
  • harness-driver: registerDriverActions(actions, driver) takes an ActionRegistry, not relay; the driver CLI group doesn't exist (replaced with real local agent commands).
  • reference-cli: fixed cloud connect <provider>, added cloud session, cloud worker, workspace active, and a Fleet section.
  • fleets: handlers_live is on fleet nodes, not fleet status.

Deleted

  • reference-openclaw.mdx — documented a nonexistent openclaw export; no OpenClaw code exists in packages/ or crates/. Removed the page, nav entries, icon mapping, and dangling OpenClaw mentions.

Remaining unverifiable areas

  • Inbound webhook POST body ({ message, author }) is enforced by the relay server (not in this repo); the SDK side is verified. Left as the documented external contract.
  • Whether the relay emits each event name to outbound webhooks is a server contract; narrowed the documented list to canonical relay event names.

🤖 Generated with Claude Code


Generated by Claude Code

Review in cubic

claude added 7 commits June 19, 2026 04:28
- Actions must be registered on an agent client (not the workspace client)
  to be exposed as MCP tools; fix quickstart, actions, events,
  event-handlers, orchestrating-with-actions examples
- Fix envelope.from.handle -> envelope.from?.name (no handle field)
- Fix action-handler caller agent.handle -> agent.name
- Correct RelayEvent union, envelope, and event-name vocabulary in events
- Fix delivery.failed listener to use nested session-event fields

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXcjNrVVjkgUakMmM89JgB
- agent-relay-mcp: real tool names (post_message, send_dm, reply_to_thread,
  add_reaction, check_inbox, mark_message_read), 'agent-relay mcp' has no
  subcommands and reads env, fix runtime action list, durable fallbacks
- typescript-sdk: register is idempotent by default (strict opt-in), fix
  envelope.from.handle, MCP tool names, register action on agent client
- fleets: handlers_live is on 'fleet nodes', not 'fleet status'

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXcjNrVVjkgUakMmM89JgB
- session-capabilities: real AgentSessionStatus (5 values), correct event
  union field shapes (usage, session.*, message.*, terminal.screen, tool.*)
- delivery: real DeliveryRunner class + AgentDeliveryAdapter interface,
  delivery events as nested session events, accurate retry behavior
- harnesses: real HarnessCreateContext/AgentIdentity, normalizeAgentIdentity,
  create({relay}) returns a handle (no sendMessage) -> use relay.messages.send
- harness-driver: registerDriverActions takes ActionRegistry not relay; real
  'local agent' CLI commands; agent.attach note
- remove reference-openclaw (no openclaw export exists) + nav entries and
  dangling OpenClaw mentions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXcjNrVVjkgUakMmM89JgB
- reference-cli: correct 'cloud connect <provider>' description, add cloud
  session, cloud worker, workspace active, and a Fleet command section
- cli-overview: workflow file types include .js and .sh
- introduction/typescript-sdk: real MCP tool names, register spawn action on
  agent client, caller.name instead of caller.handle
- migration: envelope.from?.name
- messaging: RelayMessage includes id
- drop misleading OpenClaw harness mentions (no such harness exists)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXcjNrVVjkgUakMmM89JgB
- workspaces: real RelayWorkspaceInfo/AgentIdentity shapes, register is
  idempotent by default, claude.create returns a handle not a client
- webhooks: canonical outbound event names (agent.status.idle), drop
  unverifiable delivery.* names
- migration: register idempotent-by-default wording

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXcjNrVVjkgUakMmM89JgB
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR makes broad documentation-only corrections across 20+ Agent Relay docs pages: action registration is moved from the workspace client to agent clients, event/envelope/session type shapes are updated, MCP tool names are renamed, the fictional reference-openclaw page is removed from navigation, harness and delivery contracts are revised, and three agent trajectory tracking artifacts are added.

Changes

Agent Relay Docs Alignment

Layer / File(s) Summary
Agent trajectory tracking artifacts
.agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm.trace.json, .agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm/summary.md, .agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm/trajectory.json
Adds three trajectory tracking artifacts: a trace JSON recording edited file ranges and revision hash, a completion summary with audit decisions, and a full agent decision log with retrospective.
Navigation: remove reference-openclaw, add new doc slugs
web/lib/docs-nav.ts, web/components/docs/DocsNav.tsx, web/content/docs/reference-openclaw.mdx
Removes the OpenClaw adapter page and its nav/icon entry; adds icon mappings for cli-on-the-relay, reference-cli, and reference-broker-api; moves reference-openclaw out of current slugs and adds three new hidden legacy slugs.
Core event/envelope/session type contracts
web/content/docs/events.mdx, web/content/docs/session-capabilities.mdx, web/content/docs/harnesses.mdx, web/content/docs/messaging.mdx
Rewrites RelayEvent and RelayEventEnvelope with optional fields and discriminated RelayMessageTarget; introduces ActionCaller and SessionCaller; renames AgentStatusAgentSessionStatus; reworks AgentSessionEvent payloads and HarnessInitContext/HarnessCreateContext interfaces; adds RelayMessage.id.
Action registration: relay → agent client across all docs
web/content/docs/actions.mdx, web/content/docs/event-handlers.mdx, web/content/docs/events.mdx, web/content/docs/orchestrating-with-actions.mdx, web/content/docs/quickstart.mdx, web/content/docs/typescript-sdk.mdx
Switches all action registration examples from relay.registerAction(...) to agent-client methods (coordinator/planner/taskManager), changes caller field from .handle to .name, and updates the quickstart failure listener to action.failed.
Delivery contract: DeliveryRunner class, AgentDeliveryAdapter, retry rules
web/content/docs/delivery.mdx, web/content/docs/event-handlers.mdx
Replaces old DeliveryRunner type with a class (start/stop), expands AgentDeliveryAdapter with lifecycle/injection/interrupt/capabilities fields, updates DeliveryEvent to messageId-centric payloads, revises retry to thrown-error-only, and updates delivery listener example to nested e.event.* shape.
MCP server, tool names, CLI commands, and runtime integration
web/content/docs/agent-relay-mcp.mdx, web/content/docs/cli-overview.mdx, web/content/docs/reference-cli.mdx, web/content/docs/typescript-sdk.mdx
Rewrites MCP startup to stdio env-var model; renames messaging tools to post_message, reply_to_thread, check_inbox, mark_message_read, invoke_action, list_actions; adds workspace active, cloud whoami, cloud worker, and fleet CLI commands; documents registerDriverActions for driver actions.
Harness context, workspace register idempotency, and harness-driver docs
web/content/docs/harnesses.mdx, web/content/docs/workspaces.mdx, web/content/docs/harness-driver.mdx, web/content/docs/typescript-sdk.mdx, web/content/docs/migration.mdx
Updates harness context interfaces; rewrites prebuilt harness usage (HarnessAgent as predicate handle, not messaging client); documents relay.workspace.register idempotency and strict mode; wires registerDriverActions through ActionRegistry; renames "OpenClaw And External Adapters" heading.
Cross-cutting: from.handlefrom?.name and event vocabulary
web/content/docs/messaging.mdx, web/content/docs/migration.mdx, web/content/docs/threads.mdx, web/content/docs/introduction.mdx, web/content/docs/webhooks.mdx, web/content/docs/fleets.mdx, web/content/docs/typescript-sdk.mdx
Replaces all envelope.from.handle references with envelope.from?.name; updates webhooks event list (agent.status.idle replaces agent.idle, removes delivery.*); removes OpenClaw mentions from introduction; updates fleet node confirmation snippet.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • khaliqgant

🐇 Hop, hop, hooray!
The docs have been aligned today,
from?.name where .handle once stood,
planner.registerAction — as it should!
OpenClaw is gone, the path is clear,
A tidy relay garden this year! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'docs: align web/content/docs with actual SDK/CLI implementation' accurately summarizes the main change—auditing and correcting documentation files against actual implementation.
Description check ✅ Passed The description comprehensively details the audit, cross-cutting bugs fixed, type definitions rewritten, commands/tools corrected, deletions made, and remaining unverifiable areas.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/bold-mendel-jpjj0f

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 and usage tips.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request audits and updates the documentation across various MDX files to align with the actual SDK, CLI, and harness implementations. Key updates include clarifying that action registration must occur on an agent client to be exposed via MCP, correcting event and envelope shapes, updating MCP tool names, and removing the fictional reference-openclaw page. A review comment suggests adding a defensive check in the TypeScript SDK documentation example to ensure envelope.from?.name is defined before sending a message, preventing potential routing issues to @undefined.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 150 to 155
if (envelope.channel?.name === 'reviews') {
await planner.sendMessage({
to: `@${envelope.from.handle}`,
to: `@${envelope.from?.name}`,
text: `Saw your message ${message.messageId}.`,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In the message.created listener example, envelope.from is optional and can be undefined. Accessing envelope.from?.name inside the template literal without a guard will result in sending a message to the routing target "@undefined" if from is not present. Adding a defensive check for envelope.from?.name in the if condition prevents this issue.

  if (envelope.channel?.name === 'reviews' && envelope.from?.name) {
    await planner.sendMessage({
      to: `@${envelope.from.name}`,
      text: `Saw your message ${message.messageId}.`,
    });
  }

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 827b4adfef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +29 to +30
Register on an **agent client** — the value returned by `relay.workspace.register(...)` or a harness
`create(...)`. The handler agent's identity is the descriptor's `handler_agent`, which is what registers the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't suggest harness handles can register actions

claude.create({ relay }) and the other prebuilt harness create calls return a HarnessAgent with identity plus status/tools, not a RelayAgentClient; the implementation builds it with createAgentHandle and it has no registerAction. Following this wording, users will try to expose an MCP action from a harness-created handle and get undefined instead of a relay-wired action. Limit this guidance to live agent clients from workspace.register/reconnect (or other APIs that actually return RelayAgentClient).

Useful? React with 👍 / 👎.

Comment on lines +220 to +222
await relay.messages.send({
from: planner,
to: '#reviews',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid documenting from sends for tokenless harness handles

This example uses planner from claude.create({ relay }), but that handle does not carry an agent token; relay.messages.send({ from }) only switches to an agent-scoped client when from.token exists, otherwise it falls back to the workspace client, whose messages.send requires an agent client and throws. Users copying this prebuilt-harness example will not be able to send the channel message on behalf of the spawned agent.

Useful? React with 👍 / 👎.

Comment on lines +25 to +27
`registerDriverActions(actions, driver)` takes an `AgentRelayActions` registry, not the `AgentRelay` facade.
Pass the same registry to `createWorkspace` so the actions register on the relay (and `relay.action(...)`
listeners fire):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't claim driver actions are relay-registered

Passing the registry into createWorkspace does not publish actions to the relay: registerDriverActions(actions, driver) only calls ActionRegistry.register, while relay/MCP exposure requires the agent-scoped registerFacadeAction path that calls commands.register with a handler agent. With the documented setup, local relay.action(...) listeners can see local invocations, but separate agent-relay mcp clients will not discover agent.create/agent.release tools.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

Preview deployed!

Environment URL
Web https://d2hfztdi3t17qz.cloudfront.net

This preview will be cleaned up when the PR is merged or closed.

@coderabbitai coderabbitai 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.

Actionable comments posted: 6

🧹 Nitpick comments (1)
.agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm/summary.md (1)

5-5: 💤 Low value

Add commas after year in dates.

Lines 5–6 follow month-day-year date format; AP style guide convention calls for a comma after the year when followed by additional time information.

🎨 Suggested fix
- > **Started:** June 19, 2026 at 04:19 AM
- > **Completed:** June 19, 2026 at 04:44 AM
+ > **Started:** June 19, 2026, at 04:19 AM
+ > **Completed:** June 19, 2026, at 04:44 AM

Also applies to: 6-6

🤖 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 @.agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm/summary.md
at line 5, The dates on lines 5 and 6 are missing commas after the year
according to AP style guide conventions. In both instances where a date in
month-day-year format is followed by time information, add a comma after the
year (after 2026). Update "June 19, 2026 at 04:19 AM" to "June 19, 2026, at
04:19 AM" and apply the same formatting to the date on line 6.
🤖 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 `@web/content/docs/delivery.mdx`:
- Around line 130-133: In the documentation for the `stop()` method behavior,
replace the phrase "ends the loop" with wording that clarifies it only requests
shutdown by setting a flag rather than immediately terminating the loop. The
method exits the loop after the next inbox subscription yields, not
synchronously, so the description should accurately reflect that `stop()`
initiates shutdown asynchronously rather than guaranteeing immediate termination
or disconnect behavior.
- Around line 176-179: The error message template in the delivery.failed
listener callback assumes deliveryId is always present, but DeliveryEvent
declares it as optional, which can result in "Delivery undefined failed..."
messages. Modify the text property of the planner.sendMessage call to use the
required messageId as the primary reference instead of deliveryId, optionally
including deliveryId only if it's available to avoid undefined values in the
message.

In `@web/content/docs/harness-driver.mdx`:
- Line 25: Line 25 of the harness-driver.mdx documentation incorrectly
references AgentRelayActions as the parameter type for registerDriverActions
function, but the example code and current API use ActionRegistry. Replace
AgentRelayActions with ActionRegistry on line 25 to align the documentation with
the actual implementation and maintain consistency throughout the example.

In `@web/content/docs/reference-cli.mdx`:
- Line 174: The command example in the table row for agent-relay cloud worker
contains escaped pipes with backslashes (register\|start\|status\|logs) which
render literally with the backslashes visible, making it invalid for users to
copy and paste. Remove the backslash escape characters from the pipe separators
so they appear as plain pipes, or alternatively split the single row into
multiple rows with individual command options (register, start, status, logs) to
make the syntax clear and copyable.

In `@web/content/docs/session-capabilities.mdx`:
- Around line 196-238: The documentation states on line 196 that every variant
of AgentSessionEvent carries optional fields `at?`, `agent?`, and `metadata?`,
but the `AgentSessionEvent` union type definition (lines 210-238) does not
include these fields in the type declaration. Update the `AgentSessionEvent`
type to include these three optional base fields in each union variant, either
by adding them explicitly to each variant or by using an intersection type with
a base type containing these fields, so the type definition matches the
documented contract.

In `@web/content/docs/workspaces.mdx`:
- Around line 94-95: The documentation currently instructs users to persist the
`planner.token` without explicitly marking it as a sensitive credential. Add
clear language in the workspaces.mdx file around the section mentioning
`planner.token` to explicitly call out that this token is a secret and must be
stored securely. Include guidance warning users not to hardcode, log, or commit
this token to source control, and recommend secure storage practices such as
environment variables or dedicated secret management systems.

---

Nitpick comments:
In @.agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm/summary.md:
- Line 5: The dates on lines 5 and 6 are missing commas after the year according
to AP style guide conventions. In both instances where a date in month-day-year
format is followed by time information, add a comma after the year (after 2026).
Update "June 19, 2026 at 04:19 AM" to "June 19, 2026, at 04:19 AM" and apply the
same formatting to the date on line 6.
🪄 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: b9d2f99a-fa13-4559-9da0-a24b2bdbacee

📥 Commits

Reviewing files that changed from the base of the PR and between 0eaa22f and 8be9ce5.

📒 Files selected for processing (26)
  • .agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm.trace.json
  • .agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm/summary.md
  • .agentworkforce/trajectories/completed/2026-06/traj_mnj85uiykwgm/trajectory.json
  • web/components/docs/DocsNav.tsx
  • web/content/docs/actions.mdx
  • web/content/docs/agent-relay-mcp.mdx
  • web/content/docs/cli-overview.mdx
  • web/content/docs/delivery.mdx
  • web/content/docs/event-handlers.mdx
  • web/content/docs/events.mdx
  • web/content/docs/fleets.mdx
  • web/content/docs/harness-driver.mdx
  • web/content/docs/harnesses.mdx
  • web/content/docs/introduction.mdx
  • web/content/docs/messaging.mdx
  • web/content/docs/migration.mdx
  • web/content/docs/orchestrating-with-actions.mdx
  • web/content/docs/quickstart.mdx
  • web/content/docs/reference-cli.mdx
  • web/content/docs/reference-openclaw.mdx
  • web/content/docs/session-capabilities.mdx
  • web/content/docs/threads.mdx
  • web/content/docs/typescript-sdk.mdx
  • web/content/docs/webhooks.mdx
  • web/content/docs/workspaces.mdx
  • web/lib/docs-nav.ts
💤 Files with no reviewable changes (3)
  • web/content/docs/reference-openclaw.mdx
  • web/components/docs/DocsNav.tsx
  • web/lib/docs-nav.ts

Comment on lines +130 to +133
`start()` requires `messaging.capabilities.serverDeliveryState` and throws `RelayCapabilityError` otherwise.
It consumes `messaging.inbox.subscribe(...)`, calls the target for each item, then `ack`s, `defer`s, or
`fail`s the inbox item based on the returned `InjectionResult`. A thrown error is failed with `retry: true`;
an adapter that returns `status: 'failed'` is failed with `retry: false`. `stop()` ends the loop.

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify that stop() only requests shutdown.

The implementation only flips a stop flag and exits after the inbox subscription yields again, so “ends the loop” overpromises immediate termination/disconnect behavior.

Suggested wording
-`fail`s the inbox item based on the returned `InjectionResult`. A thrown error is failed with `retry: true`;
-an adapter that returns `status: 'failed'` is failed with `retry: false`. `stop()` ends the loop.
+`fail`s the inbox item based on the returned `InjectionResult`. A thrown error is failed with `retry: true`;
+an adapter that returns `status: 'failed'` is failed with `retry: false`. `stop()` requests shutdown; the
+loop exits before processing the next subscribed item.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`start()` requires `messaging.capabilities.serverDeliveryState` and throws `RelayCapabilityError` otherwise.
It consumes `messaging.inbox.subscribe(...)`, calls the target for each item, then `ack`s, `defer`s, or
`fail`s the inbox item based on the returned `InjectionResult`. A thrown error is failed with `retry: true`;
an adapter that returns `status: 'failed'` is failed with `retry: false`. `stop()` ends the loop.
`start()` requires `messaging.capabilities.serverDeliveryState` and throws `RelayCapabilityError` otherwise.
It consumes `messaging.inbox.subscribe(...)`, calls the target for each item, then `ack`s, `defer`s, or
`fail`s the inbox item based on the returned `InjectionResult`. A thrown error is failed with `retry: true`;
an adapter that returns `status: 'failed'` is failed with `retry: false`. `stop()` requests shutdown; the
loop exits before processing the next subscribed item.
🤖 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 `@web/content/docs/delivery.mdx` around lines 130 - 133, In the documentation
for the `stop()` method behavior, replace the phrase "ends the loop" with
wording that clarifies it only requests shutdown by setting a flag rather than
immediately terminating the loop. The method exits the loop after the next inbox
subscription yields, not synchronously, so the description should accurately
reflect that `stop()` initiates shutdown asynchronously rather than guaranteeing
immediate termination or disconnect behavior.

Comment on lines +176 to +179
relay.addListener('delivery.failed', (e) =>
planner.sendMessage({
to: '#ops',
text: `Delivery ${event.deliveryId} failed for ${event.messageId}: ${event.reason}.`,
text: `Delivery ${e.event.deliveryId} failed for ${e.event.messageId}: ${e.event.reason}.`,

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid assuming deliveryId is present.

DeliveryEvent declares deliveryId as optional, so this example can produce Delivery undefined failed... for valid events. Use the required messageId as the primary reference.

Suggested fix
 relay.addListener('delivery.failed', (e) =>
   planner.sendMessage({
     to: '`#ops`',
-    text: `Delivery ${e.event.deliveryId} failed for ${e.event.messageId}: ${e.event.reason}.`,
+    text: `Delivery failed for ${e.event.messageId}: ${e.event.reason}.`,
   })
 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
relay.addListener('delivery.failed', (e) =>
planner.sendMessage({
to: '#ops',
text: `Delivery ${event.deliveryId} failed for ${event.messageId}: ${event.reason}.`,
text: `Delivery ${e.event.deliveryId} failed for ${e.event.messageId}: ${e.event.reason}.`,
relay.addListener('delivery.failed', (e) =>
planner.sendMessage({
to: '`#ops`',
text: `Delivery failed for ${e.event.messageId}: ${e.event.reason}.`,
})
);
🤖 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 `@web/content/docs/delivery.mdx` around lines 176 - 179, The error message
template in the delivery.failed listener callback assumes deliveryId is always
present, but DeliveryEvent declares it as optional, which can result in
"Delivery undefined failed..." messages. Modify the text property of the
planner.sendMessage call to use the required messageId as the primary reference
instead of deliveryId, optionally including deliveryId only if it's available to
avoid undefined values in the message.


Use the harness driver package when Agent Relay should manage the harness boundary for you.

`registerDriverActions(actions, driver)` takes an `AgentRelayActions` registry, not the `AgentRelay` facade.

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the same registry type name as the example/API.

Line 25 says AgentRelayActions, but the example imports and instantiates ActionRegistry, and the PR objective calls out ActionRegistry as the corrected contract.

Suggested fix
-`registerDriverActions(actions, driver)` takes an `AgentRelayActions` registry, not the `AgentRelay` facade.
+`registerDriverActions(actions, driver)` takes an `ActionRegistry`, not the `AgentRelay` facade.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`registerDriverActions(actions, driver)` takes an `AgentRelayActions` registry, not the `AgentRelay` facade.
`registerDriverActions(actions, driver)` takes an `ActionRegistry`, not the `AgentRelay` facade.
🤖 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 `@web/content/docs/harness-driver.mdx` at line 25, Line 25 of the
harness-driver.mdx documentation incorrectly references AgentRelayActions as the
parameter type for registerDriverActions function, but the example code and
current API use ActionRegistry. Replace AgentRelayActions with ActionRegistry on
line 25 to align the documentation with the actual implementation and maintain
consistency throughout the example.

| `agent-relay cloud logs` | Show cloud run logs. |
| `agent-relay cloud sync` | Sync local state with cloud. |
| `agent-relay cloud cancel` | Cancel a cloud run. |
| `agent-relay cloud worker register\|start\|status\|logs` | Manage cloud workers. |

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix escaped pipes in the cloud worker command example.

Line 174 currently renders backslashes as part of the command. Use plain separators (or split into separate rows) so users can copy valid syntax.

Suggested doc fix
-| `agent-relay cloud worker register\|start\|status\|logs` | Manage cloud workers. |
+| `agent-relay cloud worker register|start|status|logs` | Manage cloud workers. |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| `agent-relay cloud worker register\|start\|status\|logs` | Manage cloud workers. |
| `agent-relay cloud worker register|start|status|logs` | Manage cloud workers. |
🤖 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 `@web/content/docs/reference-cli.mdx` at line 174, The command example in the
table row for agent-relay cloud worker contains escaped pipes with backslashes
(register\|start\|status\|logs) which render literally with the backslashes
visible, making it invalid for users to copy and paste. Remove the backslash
escape characters from the pipe separators so they appear as plain pipes, or
alternatively split the single row into multiple rows with individual command
options (register, start, status, logs) to make the syntax clear and copyable.

Comment on lines +196 to 238
Every variant also carries the optional `AgentSessionEventBase` fields `at?`, `agent?`, and `metadata?`.

```ts
type TranscriptChunk = {
id: string;
at: Date;
at?: Date | string;
role: 'agent' | 'user' | 'system' | 'tool';
content: string;
sequence: number;
sequence?: number;
metadata?: Record<string, unknown>;
};

type SessionCaller = AgentIdentity | { name: string; id?: string; type?: 'agent' | 'human' | 'system' };

type AgentSessionEvent =
| { type: 'status.changed'; status: AgentStatus; previousStatus?: AgentStatus; reason?: string }
| { type: 'status.changed'; status: AgentSessionStatus; previousStatus?: AgentSessionStatus; reason?: string }
| { type: 'status.idle' | 'status.active' | 'status.blocked' | 'status.waiting' | 'status.offline'; reason?: string }
| { type: 'message.received' | 'message.sent'; message: RelayMessage }
| { type: 'delivery.accepted' | 'delivery.delivered'; messageId: string; deliveryId?: string }
| { type: 'delivery.deferred'; messageId: string; deliveryId?: string; availableAt: Date | string; reason?: string }
| { type: 'delivery.failed'; messageId: string; deliveryId?: string; reason: string; retryable?: boolean }
| { type: 'tool.called'; run?: string; tool: string; input?: unknown }
| { type: 'tool.completed'; run?: string; tool: string; output?: unknown; durationMs?: number }
| { type: 'tool.failed'; run?: string; tool: string; error: string; retryable?: boolean }
| { type: 'tool.output'; run?: string; tool: string; output: string }
| { type: 'message.received'; messageId: string; deliveryId?: string }
| { type: 'message.sent'; messageId: string }
| { type: 'delivery.accepted'; deliveryId: string; messageId: string }
| { type: 'delivery.delivered'; deliveryId: string; messageId: string }
| { type: 'delivery.deferred'; deliveryId: string; messageId: string; availableAt: Date | string; reason?: string }
| { type: 'delivery.failed'; deliveryId: string; messageId: string; reason: string; retryable?: boolean }
| { type: 'action.invoked'; action: string; invocationId: string }
| { type: 'action.completed'; action: string; invocationId: string; durationMs?: number }
| { type: 'action.failed'; action: string; invocationId: string; error: string; retryable?: boolean }
| { type: 'action.denied'; action: string; invocationId: string; reason: string }
| { type: 'tool.failed'; run?: string; tool: string; error: string; durationMs?: number }
| { type: 'tool.output'; run?: string; tool?: string; output: unknown }
| { type: 'action.invoked'; action: string; input?: unknown; caller?: SessionCaller }
| { type: 'action.completed'; action: string; output?: unknown; caller?: SessionCaller; durationMs?: number }
| { type: 'action.failed'; action: string; error: string; caller?: SessionCaller; durationMs?: number }
| { type: 'action.denied'; action: string; reason?: string; caller?: SessionCaller }
| { type: 'transcript.chunk'; chunk: TranscriptChunk }
| { type: 'file.changed'; path: string; operation: 'create' | 'update' | 'delete'; diff?: string }
| { type: 'command.started'; command: string; cwd?: string }
| { type: 'command.completed'; command: string; exitCode?: number; durationMs?: number }
| { type: 'command.failed'; command: string; error: string; exitCode?: number }
| { type: 'command.started'; commandId?: string; command: string; cwd?: string }
| { type: 'command.completed'; commandId?: string; command?: string; exitCode?: number; durationMs?: number }
| { type: 'command.failed'; commandId?: string; command?: string; error: string; exitCode?: number; durationMs?: number }
| { type: 'terminal.output'; stream?: 'stdout' | 'stderr' | 'combined'; text: string }
| { type: 'terminal.screen'; text: string; rows?: number; cols?: number }
| { type: 'usage.updated'; tokens?: number; costUsd?: number; metadata?: Record<string, unknown> }
| { type: 'session.started'; sessionId: string }
| { type: 'session.released'; sessionId: string; reason?: string }
| { type: 'session.resumed'; sessionId: string }
| { type: 'session.forked'; sessionId: string; parentSessionId: string }
| { type: 'log'; level: 'debug' | 'info' | 'warn' | 'error'; message: string }
| { type: 'terminal.screen'; text: string; rows?: number; columns?: number }
| { type: 'usage.updated'; usage: Record<string, number | string | boolean | null> }
| { type: 'session.started'; reason?: string }
| { type: 'session.released'; reason?: string }
| { type: 'session.resumed'; reason?: string }
| { type: 'session.forked'; child: AgentIdentity }
| { type: 'log'; level?: 'debug' | 'info' | 'warn' | 'error'; message: string }
| { type: 'error'; error: string; code?: string; retryable?: boolean };

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the documented base fields part of the shown union type.

Line 196 says every variant carries at?, agent?, and metadata?, but the AgentSessionEvent union on Lines 210-238 does not include them. This leaves the contract self-contradictory for readers.

Proposed doc-type fix
+type AgentSessionEventBase = {
+  at?: Date | string;
+  agent?: AgentIdentity;
+  metadata?: Record<string, unknown>;
+};
+
 type AgentSessionEvent =
-  | { type: 'status.changed'; status: AgentSessionStatus; previousStatus?: AgentSessionStatus; reason?: string }
+  | (AgentSessionEventBase & { type: 'status.changed'; status: AgentSessionStatus; previousStatus?: AgentSessionStatus; reason?: string })
   // ...apply AgentSessionEventBase to each variant
🤖 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 `@web/content/docs/session-capabilities.mdx` around lines 196 - 238, The
documentation states on line 196 that every variant of AgentSessionEvent carries
optional fields `at?`, `agent?`, and `metadata?`, but the `AgentSessionEvent`
union type definition (lines 210-238) does not include these fields in the type
declaration. Update the `AgentSessionEvent` type to include these three optional
base fields in each union variant, either by adding them explicitly to each
variant or by using an intersection type with a base type containing these
fields, so the type definition matches the documented contract.

Comment on lines +94 to +95
Pass `{ strict: true }` to reject an existing name. Persist an agent's token off its live client
(`planner.token`) and rehydrate it later in a fresh process with `relay.workspace.reconnect({ apiToken })`.

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Call out secure storage for persisted agent tokens.

This now tells users to persist planner.token; explicitly mark it as a secret so it does not end up in logs, docs, or source control.

Suggested fix
-Pass `{ strict: true }` to reject an existing name. Persist an agent's token off its live client
-(`planner.token`) and rehydrate it later in a fresh process with `relay.workspace.reconnect({ apiToken })`.
+Pass `{ strict: true }` to reject an existing name. Persist an agent's token off its live client
+(`planner.token`) in secure secret storage, and rehydrate it later in a fresh process with
+`relay.workspace.reconnect({ apiToken })`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Pass `{ strict: true }` to reject an existing name. Persist an agent's token off its live client
(`planner.token`) and rehydrate it later in a fresh process with `relay.workspace.reconnect({ apiToken })`.
Pass `{ strict: true }` to reject an existing name. Persist an agent's token off its live client
(`planner.token`) in secure secret storage, and rehydrate it later in a fresh process with
`relay.workspace.reconnect({ apiToken })`.
🤖 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 `@web/content/docs/workspaces.mdx` around lines 94 - 95, The documentation
currently instructs users to persist the `planner.token` without explicitly
marking it as a sensitive credential. Add clear language in the workspaces.mdx
file around the section mentioning `planner.token` to explicitly call out that
this token is a secret and must be stored securely. Include guidance warning
users not to hardcode, log, or commit this token to source control, and
recommend secure storage practices such as environment variables or dedicated
secret management systems.

@willwashburn willwashburn merged commit e5a1a40 into main Jun 19, 2026
2 checks passed
@willwashburn willwashburn deleted the claude/bold-mendel-jpjj0f branch June 19, 2026 13:40
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.

2 participants