Skip to content

docs: self-hosting guide#140

Open
willwashburn wants to merge 3 commits into
mainfrom
docs/self-hosting
Open

docs: self-hosting guide#140
willwashburn wants to merge 3 commits into
mainfrom
docs/self-hosting

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Adds docs/self-hosting.md — the guide for running Relaycast yourself as a single Node + SQLite process via the relaycast-engine bin (@relaycast/engine). No Cloudflare, no external services.

Covers, accurate to what actually ships (1.1.7):

  • Install/run: npx @relaycast/engine or global relaycast-engine.
  • Config: the real flags (--db/--port/--base-url/--env) + env (RELAYCAST_DB_PATH/PORT/RELAYCAST_ENV); migrations run on boot; telemetry off by default.
  • First workspace: bootstrap over the API (POST /v1/workspacesrk_live_…), register agents (at_live_…).
  • Connecting: SDK / WebSocket (/v1/ws) / MCP (/mcp + x-relay-api-key) / CLI.
  • Files: local-fs storage + HMAC-signed /_relayfiles URLs (mirrors the hosted presigned-R2 flow).
  • Production: Caddy/nginx (with WS upgrade headers), systemd, a build-your-own Dockerfile.
  • Upgrades & backups.
  • Honest limitations: single-process / no horizontal scale-out, in-process queue + cron, counters reset on restart — plus a "what you DON'T get vs hosted" table (billing, multi-tenant admin, scaling, analytics).

Linked from the README (new Self-Hosting section).

Verified the documented quick-start end-to-end: the server boots, and the workspace-create curl returns the rk_live_ key + workspace_id exactly as shown.

🤖 Generated with Claude Code

Single Node + SQLite self-host of @relaycast/engine via the relaycast-engine bin:
install/run, config (flags + env), first-workspace bootstrap over the API,
client connection (SDK/WS/MCP), local-fs files, production (Caddy/nginx/systemd/
Docker), upgrades/backups, and an honest limitations + what-you-dont-get-vs-hosted
section. Linked from the README.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pullfrog
Copy link
Copy Markdown

pullfrog Bot commented May 30, 2026

Pullfrog stalled

The agent stopped emitting events for 301s and was killed by the activity-timeout watchdog. 55 events were processed before the failure.

Recent agent stderr
INFO  2026-05-30T03:31:33 +16ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:33 +16ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:33 +16ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:33 +40ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:33 +30ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +164ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +8ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +2ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +11ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +15ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +17ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +18ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +19ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +23ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +27ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:34 +9ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:35 +1800ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:37 +1125ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:37 +21ms service=bus type=message.part.delta publishing
INFO  2026-05-30T03:31:38 +1779ms service=bus type=message.part.delta publishing

Pullfrog  | Rerun failed job ➔View workflow run | via Pullfrog | Using Kimi K2𝕏

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

Review Change Stack

Warning

Review limit reached

@agent-relay-bot[bot], we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 48 minutes and 54 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: eeacf499-ce4d-4801-ab8a-2987a59521df

📥 Commits

Reviewing files that changed from the base of the PR and between 8d2533e and 190df7d.

📒 Files selected for processing (2)
  • .trajectories/index.json
  • docs/self-hosting.md
📝 Walkthrough

Walkthrough

Adds README quick-start and a new docs/self-hosting.md for running Relaycast as a single Node + SQLite process. Also introduces Relay-side A2A part coercion, runtime guards for MCP WebSocket events, and safer event normalization and validation in the TypeScript SDK and agent route.

Changes

Self-Hosting Guide + Runtime Safety

Layer / File(s) Summary
Self-hosting guide and README
README.md, docs/self-hosting.md
README adds a Self-Hosting quick-start. docs/self-hosting.md documents prerequisites, install/run (npx & global), CLI flags (--db,--port,--base-url,--env) and precedence, idempotent migrations, workspace/agent API steps, SDK/WebSocket/MCP usage, HMAC file URLs, proxy examples (Caddy/nginx), systemd/Docker snippets, upgrade/backup steps, limitations, parity table, and troubleshooting.
Relay A2A part coercion
packages/engine/src/engine/a2a.ts
Introduce RelayA2aPart/RelayA2aArtifact, asRelayA2aParts, and update text/attachment extraction and translateA2aToRelay to normalize parts and fallback to artifact.parts when needed.
Agent registration validation
packages/engine/src/routes/agent.ts
Replace external AgentTypeSchema import with a local Zod enum for the optional type field in registerAgentSchema.
MCP WebSocket event guards
packages/mcp/src/resources/ws-bridge.ts
Change eventToResourceUris to accept a generic ResourceEvent, add isResourceEvent/getStringEventField helpers, and early-return non-conforming events in the WS handler.
SDK runtime normalization & guarded matching
packages/sdk-typescript/src/agent.ts, relay.ts, setup.ts, ws.ts
Add MessageEventRecord, deterministic id normalization, safer matchesSubscription channel checks, guarded telemetry requested_name extraction, narrow RequestConfig.schema type, and use validated serverEvent.type when emitting WS events.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs:

"I'm a rabbit, docs in my paw,
Start Relaycast with SQLite—hurrah!
Guards in websockets, parts coerced just right,
Self-hosted server humming through the night. 🐇📦"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a self-hosting guide documentation.
Description check ✅ Passed The description directly relates to the changeset, providing detailed context about the self-hosting guide, installation, configuration, and features documented.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/self-hosting

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.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

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 introduces a comprehensive self-hosting guide for Relaycast, adding a new documentation file docs/self-hosting.md and updating the README.md with a quick-start section. The documentation covers prerequisites, installation, configuration, production setup (including reverse proxies, systemd, and Docker), and limitations. Feedback on the documentation suggests correcting the systemd service path to /usr/local/bin/ to prevent execution failures, and optimizing the provided Dockerfile using a multi-stage build to reduce image size and improve security.

Comment thread docs/self-hosting.md Outdated

```ini
[Service]
ExecStart=/usr/bin/relaycast-engine --db /var/lib/relaycast/relaycast.db --port 8787 --base-url https://relay.example.com
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

On most Linux distributions, globally installed npm packages (via npm install -g) are placed in /usr/local/bin/ rather than /usr/bin/. Using /usr/bin/relaycast-engine will likely cause the systemd service to fail to start with a 203/EXEC error. Updating this path to /usr/local/bin/relaycast-engine ensures compatibility with standard Node.js installations.

Suggested change
ExecStart=/usr/bin/relaycast-engine --db /var/lib/relaycast/relaycast.db --port 8787 --base-url https://relay.example.com
ExecStart=/usr/local/bin/relaycast-engine --db /var/lib/relaycast/relaycast.db --port 8787 --base-url https://relay.example.com

Comment thread docs/self-hosting.md
Comment on lines +173 to +180
FROM node:20-bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends build-essential python3 \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g @relaycast/engine
VOLUME /data
EXPOSE 8787
ENV RELAYCAST_DB_PATH=/data/relaycast.db PORT=8787
ENTRYPOINT ["relaycast-engine"]
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

The current Dockerfile installs build dependencies (build-essential and python3) which are required to compile the native better-sqlite3 module during installation, but are not needed at runtime. Keeping these in the final image significantly increases the image size and the security attack surface.

Using a multi-stage build allows you to compile the dependencies in a builder stage and copy only the compiled node modules and binary to a clean runtime stage, keeping the final production image slim and secure.

Suggested change
FROM node:20-bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends build-essential python3 \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g @relaycast/engine
VOLUME /data
EXPOSE 8787
ENV RELAYCAST_DB_PATH=/data/relaycast.db PORT=8787
ENTRYPOINT ["relaycast-engine"]
FROM node:20-bookworm-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends build-essential python3 && rm -rf /var/lib/apt/lists/*
RUN npm install -g @relaycast/engine
FROM node:20-bookworm-slim
COPY --from=builder /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=builder /usr/local/bin/relaycast-engine /usr/local/bin/relaycast-engine
VOLUME /data
EXPOSE 8787
ENV RELAYCAST_DB_PATH=/data/relaycast.db PORT=8787
ENTRYPOINT ["relaycast-engine"]

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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: a1a8ff4141

ℹ️ 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 thread docs/self-hosting.md
Comment on lines +177 to +180
VOLUME /data
EXPOSE 8787
ENV RELAYCAST_DB_PATH=/data/relaycast.db PORT=8787
ENTRYPOINT ["relaycast-engine"]
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 Persist the upload directory in the Docker example

With this Dockerfile/run command, only /data is mounted, but the Node adapter writes uploaded blobs to process.cwd()/relaycast-files by default and the image never sets WORKDIR /data or a file-directory option. In the documented Docker deployment, uploaded files therefore land in an unmounted /relaycast-files inside the container and are lost when the container is recreated, even though the database is persisted under /data.

Useful? React with 👍 / 👎.

Comment thread docs/self-hosting.md Outdated
Comment on lines +108 to +110
- **Real-time WebSocket**: `ws://your-host:8787/v1/ws?token=<rk_live_ or at_live_>`
(an agent token streams that agent's events; a workspace key streams the
workspace event stream).
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 Enable workspace stream before documenting rk_live_ WebSockets

For a fresh self-host started by this guide, rk_live_ WebSocket connections do not stream by default: startServer leaves workspaceStreamEnabled unset, and /v1/ws rejects workspace keys unless the workspace stream override is enabled. Users following this URL with the workspace key they just created will get a 404 until they call PUT /v1/workspace/stream with { "enabled": true } (or they use an agent token), so the connection instructions need to include that prerequisite.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@docs/self-hosting.md`:
- Line 13: Update the broken in-page link by making the fragment and heading
match: either change the link text "[Limitations](`#limitations`)" to use the
generated anchor "[Limitations](`#8-limitations`)" or rename the heading "## 8.
Limitations" to "## Limitations" so the existing "[Limitations](`#limitations`)"
link resolves; ensure the adjusted fragment exactly matches the heading slug
used by GitHub (e.g., "8-limitations") and update any other references if
present.
- Around line 48-50: The fenced code block containing "Relaycast self-host
listening on http://localhost:8787 (db: ./relaycast.db)" lacks a language
identifier and triggers MD040; update that fenced block to include a language
(e.g., add "text" or "bash" after the opening ``` fence) so the block becomes
```text (or ```bash) before the content to satisfy the linter.
🪄 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: 1095739f-f1b5-4ba2-9ac5-7020139c73fc

📥 Commits

Reviewing files that changed from the base of the PR and between a873784 and a1a8ff4.

📒 Files selected for processing (2)
  • README.md
  • docs/self-hosting.md

Comment thread docs/self-hosting.md Outdated
Comment thread docs/self-hosting.md
Comment on lines +48 to +50
```
Relaycast self-host listening on http://localhost:8787 (db: ./relaycast.db)
```
Copy link
Copy Markdown

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

Add a language identifier to the fenced block.

The code fence at Line 48 has no language, which trips markdown linting (MD040). Use text (or bash if you want it treated as command output).

Suggested patch
-```
+```text
 Relaycast self-host listening on http://localhost:8787 (db: ./relaycast.db)
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@docs/self-hosting.md` around lines 48 - 50, The fenced code block containing
"Relaycast self-host listening on http://localhost:8787 (db: ./relaycast.db)"
lacks a language identifier and triggers MD040; update that fenced block to
include a language (e.g., add "text" or "bash" after the opening ``` fence) so
the block becomes ```text (or ```bash) before the content to satisfy the linter.

@github-actions
Copy link
Copy Markdown

Preview deployed!

Environment URL
API https://pr140-api.relaycast.dev
Health https://pr140-api.relaycast.dev/health
Observer https://pr140-observer.relaycast.dev/observer

This preview shares the staging database and will be cleaned up when the PR is merged or closed.

Run E2E tests

npm run e2e -- https://pr140-api.relaycast.dev --ci

Open observer dashboard

https://pr140-observer.relaycast.dev/observer

@agent-relay-bot
Copy link
Copy Markdown
Contributor

Reviewed PR #140 and fixed the issues I found.

Changes made:

  • Corrected docs/self-hosting.md so workspace-key WebSocket streams are documented as disabled by default and require PUT /v1/workspace/stream.
  • Added the restart limitation for the in-memory workspace-stream override.
  • Fixed TypeScript build failures in SDK/MCP/engine caused by Zod type inference across package boundaries by adding local schema/event narrowing.

Local checks run:

  • npm run -w @relaycast/sdk build
  • npx turbo build --filter=@relaycast/engine
  • npx turbo test --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine
  • npx turbo lint --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine

Lint completed with warnings only in pre-existing engine files.

@agent-relay-bot
Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed 8d2533e to this PR. The notes below describe what changed.

Reviewed PR #140 and fixed the issues I found.

Changes made:

  • Corrected docs/self-hosting.md so workspace-key WebSocket streams are documented as disabled by default and require PUT /v1/workspace/stream.
  • Added the restart limitation for the in-memory workspace-stream override.
  • Fixed TypeScript build failures in SDK/MCP/engine caused by Zod type inference across package boundaries by adding local schema/event narrowing.

Local checks run:

  • npm run -w @relaycast/sdk build
  • npx turbo build --filter=@relaycast/engine
  • npx turbo test --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine
  • npx turbo lint --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine

Lint completed with warnings only in pre-existing engine files.

Copy link
Copy Markdown
Contributor

@agent-relay-bot agent-relay-bot Bot left a comment

Choose a reason for hiding this comment

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

pr-reviewer applied fixes — committed and pushed 8d2533e to this PR. The notes below describe what changed.

Reviewed PR #140 and fixed the issues I found.

Changes made:

  • Corrected docs/self-hosting.md so workspace-key WebSocket streams are documented as disabled by default and require PUT /v1/workspace/stream.
  • Added the restart limitation for the in-memory workspace-stream override.
  • Fixed TypeScript build failures in SDK/MCP/engine caused by Zod type inference across package boundaries by adding local schema/event narrowing.

Local checks run:

  • npm run -w @relaycast/sdk build
  • npx turbo build --filter=@relaycast/engine
  • npx turbo test --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine
  • npx turbo lint --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine

Lint completed with warnings only in pre-existing engine files.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 2 files

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="docs/self-hosting.md">

<violation number="1" location="docs/self-hosting.md:13">
P2: Broken in-page link: `#limitations` won't resolve because the target heading is `## 8. Limitations`, which GitHub renders as anchor `#8-limitations`. Either update the link to `#8-limitations` or rename the heading to `## Limitations`.</violation>

<violation number="2" location="docs/self-hosting.md:162">
P2: The `ExecStart` path should be `/usr/local/bin/relaycast-engine`. On most Linux distributions, `npm install -g` installs binaries to `/usr/local/bin/`, not `/usr/bin/`. Using `/usr/bin/relaycast-engine` will cause systemd to fail with a `203/EXEC` error.</violation>

<violation number="3" location="docs/self-hosting.md:179">
P2: The Docker example only mounts `/data` for the database, but uploaded files are written to `<cwd>/relaycast-files` by default. Since `WORKDIR` is not set (defaults to `/`), uploaded files land in `/relaycast-files` inside the container — an unmounted path — and are lost when the container is recreated. Either set `WORKDIR /data` or add a `RELAYCAST_FILES_PATH` env pointing into the mounted volume.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread docs/self-hosting.md Outdated
Comment thread docs/self-hosting.md Outdated
Comment thread docs/self-hosting.md
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/mcp/src/resources/ws-bridge.ts (1)

6-15: ⚡ Quick win

Replace ad-hoc event runtime guards with a local Zod schema in packages/mcp/src/resources/ws-bridge.ts

packages/mcp already depends on and uses Zod (safeParse/parse patterns). Define a local Zod schema for the websocket event (including type and any string fields you read) and use safeParse/parse to narrow instead of typeof-based helpers like isResourceEvent/getStringEventField (and the resulting early return in WsBridge.start).

🤖 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/mcp/src/resources/ws-bridge.ts` around lines 6 - 15, Replace the
ad-hoc runtime guards isResourceEvent and getStringEventField with a local Zod
schema: define a z.object schema that requires type: z.string() and any other
string fields you read from events, import z from 'zod' locally, and then use
schema.safeParse(event) (or schema.parse where appropriate) inside
WsBridge.start to validate and narrow the event instead of typeof checks and
early returns; remove isResourceEvent/getStringEventField and update references
in WsBridge.start to use the parsed result (result.success ? result.data :
handle invalid).
packages/engine/src/engine/a2a.ts (1)

187-189: ⚡ Quick win

asRelayA2aParts cast doesn’t introduce the reported runtime risk (schema already enforces per-kind payloads)

translateA2aToRelay parses input with JsonRpcRequestSchema.safeParse / JsonRpcResponseSchema.parse, which use A2aPartSchema as a z.discriminatedUnion('kind'):

  • kind: 'file' requires a file object (including file.name)
  • kind: 'data' requires a data record

So extractTextFromParts / extractAttachmentsFromParts shouldn’t receive parts with missing file/data when coming from these parsed paths. Optional: asRelayA2aParts can be simplified to take the already-typed parts directly (drop the unknown + Array.isArray + cast).

🤖 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/engine/src/engine/a2a.ts` around lines 187 - 189, The
asRelayA2aParts function currently accepts unknown and performs an Array.isArray
check and cast, which is unnecessary because translateA2aToRelay already
validates input via JsonRpcRequestSchema/JsonRpcResponseSchema using the
discriminated A2aPartSchema; update asRelayA2aParts to accept RelayA2aPart[]
directly (remove the unknown parameter, Array.isArray guard, and cast) so
downstream helpers like extractTextFromParts and extractAttachmentsFromParts
receive correctly-typed parts without redundant runtime checks; ensure any
callers (e.g., translateA2aToRelay) are updated to pass the typed array.
🤖 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.

Nitpick comments:
In `@packages/engine/src/engine/a2a.ts`:
- Around line 187-189: The asRelayA2aParts function currently accepts unknown
and performs an Array.isArray check and cast, which is unnecessary because
translateA2aToRelay already validates input via
JsonRpcRequestSchema/JsonRpcResponseSchema using the discriminated
A2aPartSchema; update asRelayA2aParts to accept RelayA2aPart[] directly (remove
the unknown parameter, Array.isArray guard, and cast) so downstream helpers like
extractTextFromParts and extractAttachmentsFromParts receive correctly-typed
parts without redundant runtime checks; ensure any callers (e.g.,
translateA2aToRelay) are updated to pass the typed array.

In `@packages/mcp/src/resources/ws-bridge.ts`:
- Around line 6-15: Replace the ad-hoc runtime guards isResourceEvent and
getStringEventField with a local Zod schema: define a z.object schema that
requires type: z.string() and any other string fields you read from events,
import z from 'zod' locally, and then use schema.safeParse(event) (or
schema.parse where appropriate) inside WsBridge.start to validate and narrow the
event instead of typeof checks and early returns; remove
isResourceEvent/getStringEventField and update references in WsBridge.start to
use the parsed result (result.success ? result.data : handle invalid).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9bb71ad2-0a2a-4385-85bc-bf7fcd418475

📥 Commits

Reviewing files that changed from the base of the PR and between a1a8ff4 and 8d2533e.

📒 Files selected for processing (9)
  • .trajectories/index.json
  • docs/self-hosting.md
  • packages/engine/src/engine/a2a.ts
  • packages/engine/src/routes/agent.ts
  • packages/mcp/src/resources/ws-bridge.ts
  • packages/sdk-typescript/src/agent.ts
  • packages/sdk-typescript/src/relay.ts
  • packages/sdk-typescript/src/setup.ts
  • packages/sdk-typescript/src/ws.ts
💤 Files with no reviewable changes (1)
  • .trajectories/index.json
✅ Files skipped from review due to trivial changes (2)
  • packages/sdk-typescript/src/ws.ts
  • packages/sdk-typescript/src/setup.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/self-hosting.md

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 9 files (changes from recent commits).

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/engine/src/routes/agent.ts">

<violation number="1" location="packages/engine/src/routes/agent.ts:25">
P3: Reuse the shared `AgentTypeSchema` instead of duplicating the enum here. This keeps agent registration validation aligned with `packages/types/src/agent.ts`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

});

const capabilitiesSchema = z.record(z.string(), z.unknown());
const agentTypeSchema = z.enum(['agent', 'human', 'system']);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Reuse the shared AgentTypeSchema instead of duplicating the enum here. This keeps agent registration validation aligned with packages/types/src/agent.ts.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/engine/src/routes/agent.ts, line 25:

<comment>Reuse the shared `AgentTypeSchema` instead of duplicating the enum here. This keeps agent registration validation aligned with `packages/types/src/agent.ts`.</comment>

<file context>
@@ -23,10 +22,11 @@ const skillSchema = z.object({
 });
 
 const capabilitiesSchema = z.record(z.string(), z.unknown());
+const agentTypeSchema = z.enum(['agent', 'human', 'system']);
 
 const registerAgentSchema = z.object({
</file context>

@agent-relay-bot
Copy link
Copy Markdown
Contributor

Reviewed PR #140 and applied the needed fixes.

Changed:

  • Restored .trajectories/index.json to avoid unrelated metadata deletion.
  • Fixed the broken docs/self-hosting.md in-page anchor.
  • Updated the systemd ExecStart path to /usr/local/bin/relaycast-engine.
  • Added WORKDIR /data to the Docker example so default file uploads persist under the mounted volume.

Local verification:

  • npm run -w @relaycast/sdk build
  • npm run -w @relaycast/mcp build
  • npm run -w @relaycast/engine build
  • npx turbo test --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine
  • npx turbo lint --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine passed with existing engine warnings only.

@agent-relay-bot
Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed 190df7d to this PR. The notes below describe what changed.

Reviewed PR #140 and applied the needed fixes.

Changed:

  • Restored .trajectories/index.json to avoid unrelated metadata deletion.
  • Fixed the broken docs/self-hosting.md in-page anchor.
  • Updated the systemd ExecStart path to /usr/local/bin/relaycast-engine.
  • Added WORKDIR /data to the Docker example so default file uploads persist under the mounted volume.

Local verification:

  • npm run -w @relaycast/sdk build
  • npm run -w @relaycast/mcp build
  • npm run -w @relaycast/engine build
  • npx turbo test --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine
  • npx turbo lint --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine passed with existing engine warnings only.

Copy link
Copy Markdown
Contributor

@agent-relay-bot agent-relay-bot Bot left a comment

Choose a reason for hiding this comment

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

pr-reviewer applied fixes — committed and pushed 190df7d to this PR. The notes below describe what changed.

Reviewed PR #140 and applied the needed fixes.

Changed:

  • Restored .trajectories/index.json to avoid unrelated metadata deletion.
  • Fixed the broken docs/self-hosting.md in-page anchor.
  • Updated the systemd ExecStart path to /usr/local/bin/relaycast-engine.
  • Added WORKDIR /data to the Docker example so default file uploads persist under the mounted volume.

Local verification:

  • npm run -w @relaycast/sdk build
  • npm run -w @relaycast/mcp build
  • npm run -w @relaycast/engine build
  • npx turbo test --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine
  • npx turbo lint --filter=@relaycast/sdk --filter=@relaycast/mcp --filter=@relaycast/engine passed with existing engine warnings only.

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.

1 participant