diff --git a/apps/host-selfhost/web/auth-layout.tsx b/apps/host-selfhost/web/auth-layout.tsx
new file mode 100644
index 000000000..ea784f05c
--- /dev/null
+++ b/apps/host-selfhost/web/auth-layout.tsx
@@ -0,0 +1,90 @@
+import type { ReactNode } from "react";
+
+import { Wordmark } from "@executor-js/react/components/wordmark";
+
+// Split auth layout for the chromeless pages (setup, login, join): a promo
+// panel on the left, the form on the right. The panel follows design.md's
+// registry-minimal rules — graph-paper texture, mono eyebrow + index numerals,
+// grayscale only — so the first screen a person ever sees speaks the same
+// language as the app behind it. Collapses to form-only below lg.
+const PANEL_POINTS: ReadonlyArray<{ index: string; title: string; body: string }> = [
+ {
+ index: "01",
+ title: "Connect",
+ body: "OpenAPI, GraphQL, and MCP sources become tools your agent can call.",
+ },
+ {
+ index: "02",
+ title: "Control",
+ body: "Policies decide which tools run, which ask first, and which are blocked.",
+ },
+ {
+ index: "03",
+ title: "Audit",
+ body: "Every invocation is recorded, with approvals where they matter.",
+ },
+];
+
+export function AuthLayout(props: { readonly children: ReactNode }) {
+ return (
+
+
+
+
+
+
+
+ {props.children}
+
+
+ );
+}
diff --git a/apps/host-selfhost/web/login.tsx b/apps/host-selfhost/web/login.tsx
index 4d78b9703..4c56287a4 100644
--- a/apps/host-selfhost/web/login.tsx
+++ b/apps/host-selfhost/web/login.tsx
@@ -5,6 +5,7 @@ import { Input } from "@executor-js/react/components/input";
import { Label } from "@executor-js/react/components/label";
import { authClient } from "./auth-client";
+import { AuthLayout } from "./auth-layout";
import { mcpAuthorizeResumeTarget, safeReturnTo } from "../src/auth/return-to";
// Self-host login: email + password sign-in via Better Auth. On success we
@@ -54,12 +55,16 @@ export const LoginPage = () => {
};
return (
-
- {mode === "signin" ? "Sign in to your instance" : "Join with your invite code"}
+ {mode === "signin"
+ ? "Welcome back. Use your instance account."
+ : "Enter the invite code you were given."}
+
);
};
diff --git a/apps/host-selfhost/web/setup.tsx b/apps/host-selfhost/web/setup.tsx
index 91418bd21..8bc143d4b 100644
--- a/apps/host-selfhost/web/setup.tsx
+++ b/apps/host-selfhost/web/setup.tsx
@@ -5,6 +5,7 @@ import { Input } from "@executor-js/react/components/input";
import { Label } from "@executor-js/react/components/label";
import { authClient } from "./auth-client";
+import { AuthLayout } from "./auth-layout";
// First-run setup. A fresh instance has no users, so the first visitor creates
// the admin account here. The server admits the first signup into the empty org
@@ -32,15 +33,15 @@ export const SetupPage = () => {
};
return (
-
+
);
};
diff --git a/packages/react/src/components/mcp-install-card.tsx b/packages/react/src/components/mcp-install-card.tsx
index 1ef3f9f8b..0292e4a8b 100644
--- a/packages/react/src/components/mcp-install-card.tsx
+++ b/packages/react/src/components/mcp-install-card.tsx
@@ -170,7 +170,7 @@ export function McpInstallCard(props: { className?: string }) {
? isDev
? "Uses the repo-local dev CLI from any agent working directory."
: "Requires the executor CLI on your PATH."
- : "Connect to executor as a remote MCP server over streamable HTTP.";
+ : "Paste this into Claude Code, Cursor, or any MCP client, and your agent gets every tool you connect here.";
const advancedControls = (
@@ -224,9 +224,10 @@ export function McpInstallCard(props: { className?: string }) {
key={key}
title={label}
aria-label={label}
+ role="img"
style={{ zIndex: SUPPORTED_AGENTS.length - index }}
className={cn(
- "flex h-6 items-center justify-center rounded-md border border-border/60 bg-background px-1.5 transition-[margin] duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]",
+ "flex h-6 items-center justify-center rounded-md border border-border/60 bg-background px-1.5 text-muted-foreground transition-[margin] duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]",
index > 0 && "-ml-2 group-hover/agents:ml-1",
)}
>