Skip to content

Add OpenClaw web pages with static/dynamic split and prod deploy workflow#485

Merged
willwashburn merged 13 commits intomainfrom
openclaw-landing-page
Mar 6, 2026
Merged

Add OpenClaw web pages with static/dynamic split and prod deploy workflow#485
willwashburn merged 13 commits intomainfrom
openclaw-landing-page

Conversation

@willwashburn
Copy link
Copy Markdown
Member

@willwashburn willwashburn commented Mar 4, 2026

Summary

  • add openclaw-web as a Next.js app (Next 16) with routes:
    • /openclaw (static, cacheable render of packages/openclaw/skill/SKILL.md)
    • /openclaw/invite/[token] (dynamic render with explicit token instructions)
  • keep skill content sourced from packages/openclaw/skill/SKILL.md (no copied skill content)
  • update token rendering behavior so invite pages:
    • preserve Step 1 (create workspace) and add a skip note when a key is present
    • inject explicit key usage into the join-existing setup step
  • move SST config into openclaw-web/sst.config.ts
  • add production deploy workflow for OpenClaw page on merges to main

Notes

  • root / returns 404; intended routes are /openclaw and /openclaw/invite/[token]
  • custom domain settings are production-focused in the deployment path

Validation

  • verified local next dev routes for /openclaw and /openclaw/invite/[token]
  • verified invite-token transformation keeps Step 1 instructions and personalizes Step 2 command

Introduce an isolated SST app under openclaw-web: add sst.config.ts to provision an OpenClaw Function (with .md text loader) and a Cloudflare-backed Router for production. Add a Lambda handler (src/openclaw.ts) that serves packages/openclaw/skill/SKILL.md as HTML and injects explicit invite_token/workspace key instructions when provided. Add markdown.d.ts, update .gitignore to ignore SST artifacts, and add a GitHub Actions workflow (deploy-openclaw-page.yml) to deploy the page on pushes to main. Update package.json/lock to include SST-related dev deps/scripts and add a set of trajectory metadata files documenting the changes.
Migrate openclaw-web to a Next.js app: add app/, components, lib/skill-markdown.ts, globals.css, next.config.mjs, next-env and package.json to serve /openclaw (static) and /openclaw/invite/[token] (SSR). Replace the prior static build script and inline markdown import with a helper that reads the canonical packages/openclaw/skill/SKILL.md and applies invite tokens; enable outputFileTracingIncludes so Next bundles the external SKILL.md. Remove legacy build/static sources and markdown typings, update SST/Next config and top-level package metadata, and add trajectory records reflecting routing and SKILL decisions. Also tweak .gitignore (remove openclaw-web/site/ line).
Reorder OpenClaw SKILL.md so "Create New Workspace" is step 1 and move "Join Existing Workspace" to step 2. Update openclaw-web/lib/skill-markdown.ts to stop wholesale replacement of the create-workspace block when an invite token is present — it now adds an advisory note under the create-workspace heading and only customizes the join-existing command/intro with the provided token. Also add trajectory records and update the .trajectories index. This keeps SKILL.md authoritative and avoids drifting rendered docs when tokens are supplied.
@willwashburn willwashburn requested a review from khaliqgant as a code owner March 4, 2026 23:44
devin-ai-integration[bot]

This comment was marked as resolved.

@willwashburn
Copy link
Copy Markdown
Member Author

Addressed both inline review findings in aa5f547:\n- switched setup-command substitution to replaceAll so troubleshooting commands are tokenized too\n- hardened SKILL.md runtime path resolution with multiple candidate roots to support Lambda/Next packaging layouts

devin-ai-integration[bot]

This comment was marked as resolved.

# Conflicts:
#	packages/openclaw/skill/SKILL.md
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new openclaw-web Next.js app to publish the canonical OpenClaw SKILL content at /openclaw (static) and /openclaw/invite/[token] (dynamic), along with SST configuration and a production deploy workflow.

Changes:

  • Introduces openclaw-web (Next.js) with static/dynamic routes that render packages/openclaw/skill/SKILL.md, plus token-based instruction injection.
  • Updates packages/openclaw/skill/SKILL.md to reorder setup steps and switch invite URLs to the new path-based route.
  • Adds SST config + a GitHub Actions workflow to deploy the OpenClaw page on merges to main, and wires the app into the monorepo workspaces.

Reviewed changes

Copilot reviewed 52 out of 55 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/openclaw/skill/SKILL.md Reorders setup sections and updates invite URLs to /openclaw/invite/<token>; copy tweaks.
package.json Adds openclaw-web workspace, adds dev:web script, adds sst devDependency.
package-lock.json Lockfile updates for new workspace + sst/Next dependencies.
openclaw-web/tsconfig.json Adds TS config for the Next.js app.
openclaw-web/sst.config.ts Defines SST Router + Nextjs component and production domain settings.
openclaw-web/package.json Declares Next/React dependencies and basic scripts.
openclaw-web/next.config.mjs Configures output file tracing to include external SKILL.md.
openclaw-web/next-env.d.ts Next TypeScript environment declarations for the app.
openclaw-web/lib/skill-markdown.ts Reads SKILL.md and injects invite-token specific instructions via string transforms.
openclaw-web/components/SkillPage.tsx Renders the page wrapper and displays the markdown content.
openclaw-web/app/page.tsx Root route returns 404 via notFound().
openclaw-web/app/openclaw/page.tsx Static /openclaw route rendering canonical SKILL.md.
openclaw-web/app/openclaw/invite/[token]/page.tsx Dynamic invite route that applies token-specific markdown transformations.
openclaw-web/app/layout.tsx Sets basic HTML layout + page metadata and imports global styles.
openclaw-web/app/globals.css Adds basic styling for the rendered page.
.trajectories/index.json Updates trajectory index timestamp and adds entries for the work done in this PR.
.trajectories/completed/2026-03/traj_zqrckxk72crk.md Records a completed trajectory related to route restructuring.
.trajectories/completed/2026-03/traj_zqrckxk72crk.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_ydyvruawxtxy.md Records a completed trajectory for migrating to Next.js.
.trajectories/completed/2026-03/traj_ydyvruawxtxy.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_v2w5gavdktck.md Records a completed trajectory for adding SST + dev script changes.
.trajectories/completed/2026-03/traj_v2w5gavdktck.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_twbd14s960dc.md Records a completed trajectory for pinning Next.js version.
.trajectories/completed/2026-03/traj_twbd14s960dc.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_ttciubcdm460.md Records a completed trajectory for static/dynamic route split + URL updates.
.trajectories/completed/2026-03/traj_ttciubcdm460.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_tt4dr55gmhpv.md Records a completed trajectory for reordering setup steps.
.trajectories/completed/2026-03/traj_tt4dr55gmhpv.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_sl9f8uw68x4p.md Records a completed trajectory related to /openclaw redirect handling.
.trajectories/completed/2026-03/traj_sl9f8uw68x4p.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_raauoa7kxj1h.md Records a completed trajectory related to routing origin errors.
.trajectories/completed/2026-03/traj_raauoa7kxj1h.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_pxfql40zgwuv.md Records a completed trajectory for running SST dev preview.
.trajectories/completed/2026-03/traj_pxfql40zgwuv.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_l2lriwaf3e9f.md Records a completed trajectory related to sourcing SKILL.md.
.trajectories/completed/2026-03/traj_l2lriwaf3e9f.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_iz9iq4300df1.md Records a completed trajectory for recording SKILL sync decision.
.trajectories/completed/2026-03/traj_iz9iq4300df1.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_isz7r4chot7w.md Records a completed trajectory for invite-token rendering adjustments.
.trajectories/completed/2026-03/traj_isz7r4chot7w.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_im6qroacmhka.md Records a completed trajectory for routing decision documentation.
.trajectories/completed/2026-03/traj_im6qroacmhka.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_gulmgt0rg4dj.md Records a completed trajectory for removing SKILL copy step.
.trajectories/completed/2026-03/traj_gulmgt0rg4dj.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_dkisssqguz7b.md Records a completed trajectory for moving token instructions into setup steps.
.trajectories/completed/2026-03/traj_dkisssqguz7b.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_66gxsc0fhsem.md Records a completed trajectory for initial SST Lambda URL approach.
.trajectories/completed/2026-03/traj_66gxsc0fhsem.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_23jmoytnrrxc.md Records a completed trajectory for copy/badge behavior adjustments.
.trajectories/completed/2026-03/traj_23jmoytnrrxc.json Trajectory metadata for the same completed task.
.trajectories/completed/2026-03/traj_1b88m050m7vd.md Records a completed trajectory for explicit invite token instructions.
.trajectories/completed/2026-03/traj_1b88m050m7vd.json Trajectory metadata for the same completed task.
.husky/pre-commit Sources NVM (if present) before running lint-staged.
.gitignore Ignores SST artifacts (.sst, openclaw-web/sst-env.d.ts).
.github/workflows/deploy-openclaw-page.yml Adds production deployment workflow for the SST/Next app on main.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread openclaw-web/lib/skill-markdown.ts Outdated
Comment on lines +54 to +57
CREATE_WORKSPACE_HEADING,
[CREATE_WORKSPACE_HEADING, '', "Since you have a key, you don't need to setup a new workspace."].join(
'\n'
)
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The injected note uses "don't need to setup"; as a verb phrase this should be "set up". Since this is user-facing copy on the invite page, update the wording to avoid the grammatical error.

Copilot uses AI. Check for mistakes.
Comment thread openclaw-web/lib/skill-markdown.ts Outdated
Comment on lines +65 to +66
.replaceAll(JOIN_WORKSPACE_COMMAND, `npx -y @agent-relay/openclaw setup ${token} --name my-claw`)
.replaceAll('Enter your workspace key (`rk_live_...`)', 'Open the shared workspace in observer');
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The replacement for the observer instructions changes Enter your workspace key (rk_live_...) to Open the shared workspace in observer, but the resulting sentence still reads "...to authenticate" without telling the user what key to enter. Consider replacing that phrase with token-specific guidance (e.g., instruct to enter the provided key) rather than removing the key-entry instruction entirely.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +40
export function applyInviteToken(markdown: string, inviteToken: string): string {
const token = inviteToken.trim();
if (!token) return markdown;

const joinWorkspaceIntro = [
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

applyInviteToken is a string-based transformation that’s easy to break when SKILL.md headings/phrasing change, and there are no automated tests covering the invite-token rendering. Add a small test suite for applyInviteToken (and ensure it runs in CI—root Vitest config currently doesn’t include openclaw-web/**) so regressions are caught automatically.

Copilot uses AI. Check for mistakes.
Comment thread openclaw-web/sst.config.ts Outdated
Comment on lines +16 to +20
? {
domain: {
name: 'agentrelay.net',
dns: sst.cloudflare.dns({ proxy: true }),
},
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The SST custom domain is set to agentrelay.net, but the canonical URLs in packages/openclaw/skill/SKILL.md point to https://agentrelay.dev/openclaw/.... Unless there is an intentional redirect/CNAME strategy, this mismatch will cause the deployed site to not match the documented invite URLs. Align the deployed domain with the documented one (or update the docs/redirects accordingly).

Copilot uses AI. Check for mistakes.

permissions:
contents: read
id-token: write
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

This workflow grants id-token: write but authenticates to AWS using long-lived access keys (not OIDC). If OIDC isn’t intended, drop the id-token permission (least privilege). If OIDC is intended, switch configure-aws-credentials to role-to-assume and remove the static AWS secrets.

Suggested change
id-token: write

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +17
type PageProps = {
params: Promise<{
token: string;
}>;
};

export default async function InvitePage({ params }: PageProps) {
const { token } = await params;
const inviteToken = decodeURIComponent(token).trim();
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

params for App Router pages is an object, not a Promise. Typing it as Promise<{ token: string }> and awaiting it is likely to break type-checking and can mask real issues. Change PageProps to params: { token: string } and remove the await.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +18
export default async function InvitePage({ params }: PageProps) {
const { token } = await params;
const inviteToken = decodeURIComponent(token).trim();
if (!inviteToken) notFound();
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

decodeURIComponent(token) can throw a URIError for malformed percent-encoding (e.g. a token containing % sequences). Right now that would turn into a 500; wrap the decode in a try/catch and call notFound() (or otherwise handle) on decode failure.

Copilot uses AI. Check for mistakes.
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 52 out of 55 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

openclaw-web/lib/skill-markdown.ts:67

  • applyInviteToken() attempts to replace the string Enter your workspace key (rk_live_...), but that text does not exist in the current packages/openclaw/skill/SKILL.md. This replacement is effectively dead code and makes the transform harder to reason about; please remove it or update it to match the actual source markdown.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +53 to +57

return markdown
.replace(CREATE_WORKSPACE_HEADING, () => [CREATE_WORKSPACE_HEADING, '', SETUP_SKIP_NOTE].join('\n'))
.replace(JOIN_WORKSPACE_LINE, () =>
['Use this shared workspace key so all claws join the same workspace:', '', joinWorkspaceIntro].join(
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

applyInviteToken() appends a note under the “Create New Workspace” heading, but it doesn't explicitly tell the reader to skip running the Step 1 command (which is still shown immediately below). Consider making the inserted note unambiguous (eg explicitly “Skip Step 1 and proceed to Step 2” when a token is provided) to prevent accidentally creating a new workspace.

Copilot uses AI. Check for mistakes.
Comment thread openclaw-web/sst.config.ts Outdated
Comment on lines +16 to +21
? {
domain: {
name: 'agentrelay.net',
dns: sst.cloudflare.dns({ proxy: true }),
},
}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

Docs in packages/openclaw/skill/SKILL.md and the PR description reference https://agentrelay.dev/openclaw/..., but the production custom domain configured here is agentrelay.net. Please confirm the intended public hostname and align either the SST domain config or the documented invite/homepage URLs so generated links don’t point at the wrong site.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +55
permissions:
contents: read

jobs:
deploy:
runs-on: ubuntu-latest
env:
AWS_REGION_INPUT: ${{ github.event_name == 'workflow_dispatch' && inputs.region || 'us-east-1' }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Validate Cloudflare token
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
if [ -z "${CLOUDFLARE_API_TOKEN}" ]; then
echo "Missing required secret: CLOUDFLARE_API_TOKEN"
exit 1
fi

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION_INPUT }}

Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

This workflow requests id-token: write but then configures AWS using long-lived AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY secrets. Consider switching to GitHub OIDC (role-to-assume) to avoid static AWS keys, or remove the unused id-token permission if static credentials are intentional.

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +86
## 2) Setup (Join Existing Workspace)

Use a shared workspace key (`rk_live_...`) so all claws join the same workspace:
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The setup commands are now inconsistent: Step 1 uses @agent-relay/openclaw@latest, but Step 2 uses @agent-relay/openclaw without @latest. This can confuse users and can also change which version npx runs depending on local caching. Consider using @latest consistently for all npx examples (or consistently omitting it).

Copilot uses AI. Check for mistakes.
Comment on lines 199 to 201
```bash
npx -y @agent-relay/openclaw@latest status
npx -y @agent-relay/openclaw@latest help
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

This troubleshooting snippet uses npx -y @agent-relay/openclaw ... while surrounding sections use @agent-relay/openclaw@latest. To avoid ambiguity (and to match the earlier docs), make the version qualifier consistent across the guide.

Copilot uses AI. Check for mistakes.
Comment thread openclaw-web/lib/skill-markdown.ts Outdated
Comment on lines +32 to +34
const SETUP_SKIP_NOTE = "Since you have a key, you don't need to set up a new workspace.";

export function readSkillMarkdown(): string {
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

readSkillMarkdown() reads SKILL.md synchronously from disk every call. On the force-dynamic invite route, this will happen on every request. Since the content is static at runtime, consider reading once at module load (or memoizing) and reusing the cached string to reduce per-request I/O.

Copilot uses AI. Check for mistakes.
@willwashburn
Copy link
Copy Markdown
Member Author

Addressed the latest review comments in d29409e:

  • hardened invite-token rendering against replacement-string edge cases by using function replacements
  • fixed invite route safety: decode errors now return 404, and token is validated against ^rk_live_[A-Za-z0-9_-]+$
  • updated observer token substitution to match current SKILL text (Authenticate with workspace key ...)
  • corrected copy to set up
  • removed unused id-token: write permission from deploy workflow
  • aligned SKILL links/domains with agentrelay.net

Note on params typing in openclaw-web/app/openclaw/invite/[token]/page.tsx: leaving params: Promise<{ token: string }> intentionally. Next 16 generated route types in this repo (openclaw-web/.next/types/routes.d.ts) define params as a Promise for App Router pages.

@willwashburn
Copy link
Copy Markdown
Member Author

Addressed the latest review comments in 325cf95:

  • applyInviteToken now replaces all rk_live_YOUR_WORKSPACE_KEY placeholders consistently (no mixed placeholder/token output)
  • Step 1 note is now explicit: skip Step 1 and continue to Step 2 when a token is provided
  • SKILL commands are now consistent on @latest where flagged (Step 2 + troubleshooting)
  • readSkillMarkdown() now returns cached module-level content (avoids per-request disk reads)

Also already fixed earlier:

  • removed id-token: write from deploy workflow (.github/workflows/deploy-openclaw-page.yml)

Left intentionally unchanged:

  • params is still typed as Promise<{ token: string }> in the App Router page, because this repo’s Next 16 generated route types define params as a Promise.

devin-ai-integration[bot]

This comment was marked as resolved.

willwashburn and others added 3 commits March 5, 2026 23:35
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 52 out of 55 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

paths:
- openclaw-web/**
- packages/openclaw/skill/SKILL.md
- .github/workflows/deploy-openclaw-page.yml
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The workflow is path-filtered to openclaw-web/** and SKILL.md, but the deploy uses npm ci at the repo root and runs the root-installed sst binary. Changes to root package.json / package-lock.json (e.g. SST version bumps) can affect the deployed output but will not trigger this workflow. Consider adding package.json and package-lock.json (and any other relevant root build files) to the on.push.paths list.

Suggested change
- .github/workflows/deploy-openclaw-page.yml
- .github/workflows/deploy-openclaw-page.yml
- package.json
- package-lock.json

Copilot uses AI. Check for mistakes.
Comment thread .trajectories/index.json
Comment on lines +579 to +585
"traj_66gxsc0fhsem": {
"title": "Create SST Lambda URL serving OpenClaw skill with invite-token behavior",
"status": "completed",
"startedAt": "2026-03-04T21:53:53.494Z",
"completedAt": "2026-03-04T21:56:15.548Z",
"path": "/Users/will/Projects/relay/.trajectories/completed/2026-03/traj_66gxsc0fhsem.json"
},
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

New trajectory entries include absolute local filesystem paths (e.g. /Users/will/Projects/relay/...). These paths are non-portable and can leak developer machine details; prefer storing paths relative to the repo root (or omit them) so the data is consistent across environments.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +37
const SKILL_PATH = resolveSkillPath();
const SKILL_MARKDOWN = fs.readFileSync(SKILL_PATH, 'utf8');

const JOIN_WORKSPACE_LINE =
'Use a shared workspace key (`rk_live_...`) so all claws join the same workspace:';
const CREATE_WORKSPACE_HEADING = '## 1) Setup (Create New Workspace)';
const OBSERVER_AUTH_LINE = 'Authenticate with workspace key (`rk_live_...`).';
const TOKEN_PLACEHOLDER = 'rk_live_YOUR_WORKSPACE_KEY';
const SETUP_SKIP_NOTE = 'Since you already have a workspace key, skip Step 1 and continue with Step 2 below.';

export function readSkillMarkdown(): string {
return SKILL_MARKDOWN;
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

SKILL.md is read and cached at module load (SKILL_MARKDOWN). With ISR (revalidate) and in local dev, updates to packages/openclaw/skill/SKILL.md won't be picked up until a full process restart/cold start, which defeats the intent of revalidation. Consider reading the file inside readSkillMarkdown() (optionally with a small in-memory cache keyed by mtime) instead of caching the contents at import time.

Copilot uses AI. Check for mistakes.
Comment on lines 151 to 154
Humans can watch workspace conversation at:
<https://agentrelay.dev/observer>
<https://agentrelay.net/observer>

Authenticate with workspace key (`rk_live_...`).
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This guide now points the Observer URL at https://agentrelay.net/observer, but the SDK/runtime generates observer links under https://observer.relaycast.dev/?key=... and the new Next app in this PR does not define a /observer route. Unless there is an external redirect already configured, this link will 404. Please update the doc to the correct Observer URL (or add/provision a /observer route/redirect on agentrelay.net).

Copilot uses AI. Check for mistakes.
Add a new OpenClaw landing page with scoped styles and a copy-instructions button, convert SkillPage to use scoped .skill-page styles, and add a dedicated /openclaw/skill route. Standardize invite and observer URLs to agentrelay.dev across SKILL.md, SDK (observerUrl/log output), and docs/examples. Update sst config to attach the production domain and simplify Next.js deployment options. Minor edits: global CSS cleanup, Next types import fix, route file rename for invite path, updated unit test expectations, and trajectory metadata files for the change trace.
@willwashburn willwashburn merged commit 57b1cb6 into main Mar 6, 2026
42 checks passed
@willwashburn willwashburn deleted the openclaw-landing-page branch March 6, 2026 21:56
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 13 additional findings in Devin Review.

Open in Devin Review

Comment on lines +10 to +14
async function handleCopy() {
await navigator.clipboard.writeText(INSTRUCTIONS_TEXT);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
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.

🟡 Unhandled promise rejection when clipboard API is unavailable

The handleCopy async function in CopyInstructionsButton awaits navigator.clipboard.writeText() without any error handling. The Clipboard API throws when called in non-secure contexts (plain HTTP), when the browser permission is denied, or when navigator.clipboard is undefined. Since React's onClick doesn't catch rejections from async handlers, this produces an unhandled promise rejection and the button silently fails without any user feedback.

Suggested change
async function handleCopy() {
await navigator.clipboard.writeText(INSTRUCTIONS_TEXT);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
async function handleCopy() {
try {
await navigator.clipboard.writeText(INSTRUCTIONS_TEXT);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Clipboard API unavailable (non-secure context, permission denied, etc.)
}
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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