From 788c116f1ed24f7db965f1e2117b9e01a6b7694c Mon Sep 17 00:00:00 2001 From: Drew Sing Date: Tue, 8 Sep 2026 14:07:31 -0400 Subject: [PATCH 1/2] feat(auth): replace the Skills box on the success page with command cards The install box on the OAuth success page drove near-zero measurable engagement. Replace it with three cards showing what the CLI can do right after sign-in: install (npx clerk@latest init), customize (clerk enable orgs), and deploy (clerk deploy), each with a copy button. The copy script now falls back to execCommand when the clipboard API rejects, which the old box's script did not. --- .changeset/auth-success-page-command-cards.md | 5 + packages/cli-core/src/lib/auth-server.ts | 110 ++++++++++-------- 2 files changed, 68 insertions(+), 47 deletions(-) create mode 100644 .changeset/auth-success-page-command-cards.md diff --git a/.changeset/auth-success-page-command-cards.md b/.changeset/auth-success-page-command-cards.md new file mode 100644 index 000000000..65d8a49ac --- /dev/null +++ b/.changeset/auth-success-page-command-cards.md @@ -0,0 +1,5 @@ +--- +"clerk": patch +--- + +Replace the Clerk Skills install box on the sign-in success page with three command cards — install, customize, and deploy — showing what the CLI can do right after authentication. diff --git a/packages/cli-core/src/lib/auth-server.ts b/packages/cli-core/src/lib/auth-server.ts index cfde3424a..692a1bc60 100644 --- a/packages/cli-core/src/lib/auth-server.ts +++ b/packages/cli-core/src/lib/auth-server.ts @@ -65,30 +65,25 @@ const PAGE_STYLE = ` .auth-page > p { margin-top: 0.75rem; } @keyframes roll-in { from { transform: rotateX(90deg); opacity: 0; } to { transform: rotateX(0deg); opacity: 1; } } @keyframes fade-in { from { opacity: 0; filter: blur(2px); } to { opacity: 1; filter: blur(0px); } } - @keyframes sparkle-pulse { 0%, 100% { opacity: 0.7; transform: scale(1); } 50% { opacity: 1; transform: scale(1.12); } } - .ai-section { margin-top: 2rem; display: flex; justify-content: center; opacity: 0; animation: fade-in 0.4s ease-out 0.85s forwards; } - .ai-installer-wrap { display: flex; flex-direction: column; align-items: center; width: 24rem; max-width: 100%; } - .ai-installer { display: flex; flex-direction: column; width: 100%; border: 1px solid var(--cli-border); border-radius: 12px; overflow: hidden; text-align: left; } - .ai-header { display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 1rem; border-bottom: 1px solid var(--cli-border); background: var(--cli-tab-bg); font-size: 12.5px; color: var(--cli-fg-muted); } - .ai-header span { color: var(--cli-fg-muted); } - .ai-learn { display: inline-flex; align-items: center; gap: 0.3rem; margin-top: 0.75rem; font-size: 12px; color: var(--cli-fg-faint); text-decoration: none; transition: color 0.15s; } - .ai-learn:hover { color: var(--cli-accent); } - .ai-learn:hover .ai-external { transform: translate(1px, -1px); } - .ai-external { width: 11px; height: 11px; flex: none; color: currentColor; transition: transform 0.2s; } - .ai-sparkle { width: 14px; height: 14px; display: inline-block; flex: none; color: var(--cli-accent); animation: sparkle-pulse 2s ease-in-out infinite; transform-origin: 50% 50%; } - .ai-code-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.7rem 0.5rem 0.7rem 1rem; background: var(--cli-code-bg); } - .ai-cmd-wrap { flex: 1; min-width: 0; overflow: hidden; -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 1.875rem), transparent 100%); mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 1.875rem), transparent 100%); } - .ai-cmd { display: block; white-space: nowrap; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; line-height: 1.1; letter-spacing: -0.02em; color: var(--cli-fg-muted); user-select: text; } - .ai-bin { color: var(--cli-fg-muted); } - .ai-mid { color: var(--cli-syntax-mid); } - .ai-target { color: var(--cli-syntax-target); font-weight: 500; } - .ai-copy { background: transparent; border: 0; width: 1.75rem; height: 1.75rem; cursor: pointer; color: var(--cli-fg-dim); border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; flex: none; transition: color 0.3s cubic-bezier(0.4,0.36,0,1), background 0.15s, transform 0.15s; } - .ai-copy:hover { color: var(--cli-fg); background: var(--cli-hover-bg); } - .ai-copy:active { transform: scale(0.92); } - .ai-copy .icon-check { display: none; color: #16a34a; } - .ai-copy.copied .icon-copy { display: none; } - .ai-copy.copied .icon-check { display: inline; } - .ai-copy.copied, .ai-copy.copied:hover { color: #16a34a; } + .cli-cards { margin-top: 2.5rem; opacity: 0; animation: fade-in 0.4s ease-out 0.85s forwards; } + .cli-cards-intro { color: var(--cli-fg-muted); } + .cli-cards-grid { margin-top: 1rem; margin-inline: auto; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.75rem; width: 52rem; max-width: 100%; } + @media (max-width: 860px) { .cli-cards-grid { grid-template-columns: 1fr; width: 24rem; } } + .cli-card { display: flex; flex-direction: column; gap: 0.5rem; border: 1px solid var(--cli-border); border-radius: 12px; padding: 1rem; text-align: left; } + .cli-card-title { display: flex; align-items: center; gap: 0.45rem; font-size: 13.5px; font-weight: 600; } + .cli-card-icon { width: 14px; height: 14px; flex: none; color: var(--cli-fg-dim); } + .cli-card-desc { flex: 1; font-size: 12.5px; line-height: 1.45; color: var(--cli-fg-muted); } + .cli-card-code { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.25rem; padding: 0.45rem 0.35rem 0.45rem 0.75rem; border: 1px solid var(--cli-border); border-radius: 8px; background: var(--cli-code-bg); } + .cli-card-code code { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; letter-spacing: -0.02em; color: var(--cli-fg); user-select: text; } + .cli-prompt { color: var(--cli-fg-faint); user-select: none; } + .cli-bin { color: var(--cli-syntax-mid); } + .copy-btn { background: transparent; border: 0; width: 1.75rem; height: 1.75rem; cursor: pointer; color: var(--cli-fg-dim); border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; flex: none; transition: color 0.3s cubic-bezier(0.4,0.36,0,1), background 0.15s, transform 0.15s; } + .copy-btn:hover { color: var(--cli-fg); background: var(--cli-hover-bg); } + .copy-btn:active { transform: scale(0.92); } + .copy-btn .icon-check { display: none; color: #16a34a; } + .copy-btn.copied .icon-copy { display: none; } + .copy-btn.copied .icon-check { display: inline; } + .copy-btn.copied, .copy-btn.copied:hover { color: #16a34a; } `; function animatedText(text: string): string { @@ -107,30 +102,45 @@ animation:roll-in 0.15s ease-out ${delay}s both;">${char}`; ); } -const SPARKLE_ICON_SVG = ``; - -const EXTERNAL_ICON_SVG = ``; +const TERMINAL_ICON_SVG = ``; const COPY_ICON_SVG = ``; const CHECK_ICON_SVG = ``; const COPY_SCRIPT = ` - function copyClerkSkill(btn) { - const cmd = document.querySelector('.ai-cmd').textContent.replace(/\\s+/g, ' ').trim(); - const reset = function () { setTimeout(function () { btn.classList.remove('copied'); }, 1500); }; - if (navigator.clipboard && window.isSecureContext) { - navigator.clipboard.writeText(cmd).then(function () { btn.classList.add('copied'); reset(); }); - } else { + function copyCmd(btn) { + const cmd = btn.parentElement.querySelector('.cli-cmd-text').textContent.replace(/\\s+/g, ' ').trim(); + const done = function () { + btn.classList.add('copied'); + setTimeout(function () { btn.classList.remove('copied'); }, 1500); + }; + const fallback = function () { const ta = document.createElement('textarea'); ta.value = cmd; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); - try { document.execCommand('copy'); btn.classList.add('copied'); reset(); } catch (e) {} + try { document.execCommand('copy'); done(); } catch (e) {} document.body.removeChild(ta); + }; + if (navigator.clipboard && window.isSecureContext) { + navigator.clipboard.writeText(cmd).then(done).catch(fallback); + } else { + fallback(); } } `; +function commandCard(title: string, description: string, commandHtml: string): string { + return `
+
${TERMINAL_ICON_SVG}${escapeHtml(title)}
+

${escapeHtml(description)}

+
+ $ ${commandHtml} + +
+
`; +} + const SUCCESS_HTML = ` Clerk CLI @@ -138,19 +148,25 @@ const SUCCESS_HTML = `
${CLERK_LOGO}

${animatedText("Authentication successful")}

-

You can close this window and return to your terminal.

-
-
-
-
${SPARKLE_ICON_SVG}Using an AI coding agent? Add Clerk Skills
-
-
- npx skills add clerk/skills -
- -
-
- Learn more about building with AI${EXTERNAL_ICON_SVG} +

You may close this window.

+
+

Set up, configure, and ship Clerk from your agent or terminal.

+
+ ${commandCard( + "Install", + "Detects your framework and sets up API keys automatically.", + `npx clerk@latest init`, + )} + ${commandCard( + "Customize", + "Turn on features like B2B Authentication with one command.", + `clerk enable orgs`, + )} + ${commandCard( + "Deploy to production", + "Register your domain, configure DNS, and go live with your app.", + `clerk deploy`, + )}
From b02d605852929a7cd1d9956ded28af9fdf44516c Mon Sep 17 00:00:00 2001 From: Max Yinger <35983235+maxyinger@users.noreply.github.com> Date: Wed, 16 Sep 2026 09:56:53 -0600 Subject: [PATCH 2/2] style(auth): restyle the OAuth success page (#481) * style(auth): restyle the OAuth success page Rework the sign-in success page on top of the command cards: - The Clerk mark drops its purple disc and follows --cli-fg, sitting in a 48px frame with a gradient fill and layered shadow. - The three cards move into a bottom banner that pins to the viewport on tall screens, with a section headline in the first column at four-up. - The headline animates per word rather than per character, and the logo, headline and close-window line settle upward as one staggered motion. - A brand-coloured conic glow sweeps the viewport edges once on load. - Dark mode gets counterparts for every token the redesign added. Co-Authored-By: Claude Opus 5 (1M context) * style(auth): settle the type scale on the success page Card titles, card descriptions and the section subheadline all sit at 13px/20px, with weight and colour carrying the hierarchy instead of size. The section headline keeps 20px with a 28px line height. Co-Authored-By: Claude Opus 5 (1M context) --------- Co-authored-by: Claude Opus 5 (1M context) --- .changeset/auth-success-page.md | 5 + packages/cli-core/src/lib/auth-server.ts | 126 +++++++++++++++-------- 2 files changed, 90 insertions(+), 41 deletions(-) create mode 100644 .changeset/auth-success-page.md diff --git a/.changeset/auth-success-page.md b/.changeset/auth-success-page.md new file mode 100644 index 000000000..c3b8e76ec --- /dev/null +++ b/.changeset/auth-success-page.md @@ -0,0 +1,5 @@ +--- +"clerk": patch +--- + +Restyle the sign-in success page with a theme-aware Clerk mark, the command cards grouped into a banner along the bottom, and a staggered entrance animation. diff --git a/packages/cli-core/src/lib/auth-server.ts b/packages/cli-core/src/lib/auth-server.ts index 692a1bc60..7fce064ec 100644 --- a/packages/cli-core/src/lib/auth-server.ts +++ b/packages/cli-core/src/lib/auth-server.ts @@ -18,15 +18,15 @@ function escapeHtml(str: string): string { .replace(/'/g, "'"); } -const CLERK_LOGO = ` - - - - - +const CLERK_LOGO = ` `; const PAGE_STYLE = ` + @property --glow-angle { syntax: ""; initial-value: 0deg; inherits: false; } * { margin: 0; padding: 0; box-sizing: border-box; } :root { color-scheme: light dark; @@ -42,6 +42,14 @@ const PAGE_STYLE = ` --cli-syntax-mid: #7c3aed; --cli-syntax-target: #2563eb; --cli-accent: #6c47ff; + --cli-logo-bg: linear-gradient(180deg, rgba(10,10,10,0) 0%, rgba(10,10,10,0.02) 100%); + --cli-logo-shadow: 0px 11px 28px -10px #00000026, 0px 4px 14px -10px #0000001a, 0px 1px 2px 0px #0000000a, 0px 0px 0px 0.5px #1313161a, inset 0px -4px 16px 0px #fff, inset 0px -4px 4px 0px #ffffff80, inset 0px 3px 5px 0px #fff, inset 0px 4px 35px -6px #0000000f; + --cli-cards-bg: rgb(246, 246, 247); + --cli-brand-purple: #6c47ff; + --cli-brand-purple-soft: #9785ff; + --cli-brand-sky: #00aee3; + --cli-brand-sky-soft: #3ad4fd; + --cli-glow-opacity: 0.7; } @media (prefers-color-scheme: dark) { :root { @@ -57,24 +65,51 @@ const PAGE_STYLE = ` --cli-syntax-mid: #c4baff; --cli-syntax-target: #70b8ff; --cli-accent: #9c87ff; + --cli-logo-bg: linear-gradient(180deg, rgba(245,245,247,0.08) 0%, rgba(245,245,247,0) 100%); + --cli-logo-shadow: 0px 11px 28px -10px #00000080, 0px 4px 14px -10px #00000059, 0px 1px 2px 0px #00000059, inset 0 0 0 1px rgba(255 255 255 / 0.04), inset 0 1px 0 0 rgba(255 255 255 / 0.04), 0 0 0 1px rgba(0 0 0 / 1); + --cli-cards-bg: #17171a; + --cli-glow-opacity: 0.22; } } - body { font-family: system-ui, -apple-system, "Segoe UI", sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; background: var(--cli-bg); color: var(--cli-fg); } - .auth-page { text-align: center; padding-block: 4rem; padding-inline: 1rem; } - .auth-page h1 { margin-top: 1.25rem; font-size: clamp(1.875rem, 4vw, 2.5rem); } - .auth-page > p { margin-top: 0.75rem; } - @keyframes roll-in { from { transform: rotateX(90deg); opacity: 0; } to { transform: rotateX(0deg); opacity: 1; } } + .page-glow { position: fixed; z-index: 0; inset: -1.5rem; pointer-events: none; border: solid 0; border-image: conic-gradient(from var(--glow-angle), var(--cli-brand-purple), var(--cli-brand-purple-soft), var(--cli-brand-sky-soft), var(--cli-brand-sky), var(--cli-brand-sky-soft), var(--cli-brand-purple-soft), var(--cli-brand-purple)) 1; opacity: var(--cli-glow-opacity); filter: blur(3rem); animation: glow-sweep 2.8s cubic-bezier(0.4, 0.36, 0, 1) both, glow-spin 2.8s linear both; } + @keyframes glow-sweep { 0% { border-width: 0; } 40% { border-width: 2.5rem; } 100% { border-width: 0; } } + @keyframes glow-spin { to { --glow-angle: 1turn; } } + body { font-family: system-ui, -apple-system, "Segoe UI", sans-serif; min-height: 100vh; background: var(--cli-bg); color: var(--cli-fg); } + .auth-page { position: relative; z-index: 1; min-height: 100dvh; text-align: center; padding-inline: 1rem; } + .auth-hero { min-height: 100dvh; display: grid; place-content: center; } + .auth-headline { position: relative; } + .intro { --intro-drop: 2rem; } + .intro h1 { animation: settle-up 0.7s cubic-bezier(0.4, 0.36, 0, 1) 1.87s both; } + .intro > p { color: var(--cli-fg-muted); animation: sub-in 0.7s cubic-bezier(0.4, 0.36, 0, 1) 1.94s both; } + .intro .clerk-logo-frame { animation: logo-in 0.6s cubic-bezier(0.4, 0.36, 0, 1) both, settle-up-logo 0.7s cubic-bezier(0.4, 0.36, 0, 1) 1.8s both; } + .clerk-logo-frame { position: absolute; left: 50%; bottom: 100%; translate: -50% 0; margin-bottom: 1.25rem; display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: 50%; background: var(--cli-logo-bg); box-shadow: var(--cli-logo-shadow); } + .clerk-logo { color: var(--cli-fg); } + .auth-page h1 { font-size: clamp(1.875rem, 4vw, 2.5rem); } + .auth-headline > p { margin-top: 0.75rem; } + @keyframes word-in { from { opacity: 0; filter: blur(14px); transform: scale(1.12); } to { opacity: 1; filter: blur(0px); transform: scale(1); } } + .word-in { display: inline-block; animation: word-in 0.9s cubic-bezier(0.4, 0.36, 0, 1) both; } @keyframes fade-in { from { opacity: 0; filter: blur(2px); } to { opacity: 1; filter: blur(0px); } } - .cli-cards { margin-top: 2.5rem; opacity: 0; animation: fade-in 0.4s ease-out 0.85s forwards; } - .cli-cards-intro { color: var(--cli-fg-muted); } - .cli-cards-grid { margin-top: 1rem; margin-inline: auto; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.75rem; width: 52rem; max-width: 100%; } - @media (max-width: 860px) { .cli-cards-grid { grid-template-columns: 1fr; width: 24rem; } } - .cli-card { display: flex; flex-direction: column; gap: 0.5rem; border: 1px solid var(--cli-border); border-radius: 12px; padding: 1rem; text-align: left; } - .cli-card-title { display: flex; align-items: center; gap: 0.45rem; font-size: 13.5px; font-weight: 600; } + @keyframes cards-in { from { opacity: 0; filter: blur(14px); transform: scale(1.05); } to { opacity: 1; filter: blur(0px); transform: scale(1); } } + @keyframes settle-up { from { transform: translateY(var(--intro-drop)); } to { transform: translateY(0); } } + @keyframes settle-up-logo { from { translate: -50% var(--intro-drop); } to { translate: -50% 0; } } + @keyframes logo-in { from { opacity: 0; scale: 1.12; } to { opacity: 1; scale: 1; } } + @keyframes sub-in { from { opacity: 0; filter: blur(6px); transform: translateY(var(--intro-drop)); } to { opacity: 1; filter: blur(0px); transform: translateY(0); } } + .cli-cards { --cli-cards-width: 68rem; margin-top: 2rem; margin-bottom: 1.5rem; opacity: 0; transform-origin: 50% -20rem; animation: cards-in 0.9s cubic-bezier(0.4, 0.36, 0, 1) 0.22s both; } + .cli-cards-intro { align-self: center; padding-left: 1.5rem; text-align: left; } + .cli-cards-intro h2 { text-wrap: balance; font-size: 1.25rem; line-height: 1.75rem; font-weight: 600; color: var(--cli-fg); } + .cli-cards-intro p { max-width: 30ch; text-wrap: balance; margin-top: 0.75rem; font-size: 0.8125rem; line-height: 1.25rem; color: var(--cli-fg-muted); } + .cli-cards-grid { margin-inline: auto; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.5rem; padding: 0.5rem; width: var(--cli-cards-width); max-width: 100%; background: var(--cli-cards-bg); border-radius: 24px; } + @media (max-width: 1100px) { .cli-cards { --cli-cards-width: 52rem; } .cli-cards-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } .cli-cards-intro { grid-column: 1 / -1; padding-block: 1.5rem 1rem; } } + @media (max-width: 860px) { .auth-hero { min-height: 72dvh; } .auth-page { padding-bottom: 2rem; } .cli-cards { --cli-cards-width: 100%; margin-top: 1.5rem; } .cli-cards-grid { grid-template-columns: 1fr; } .cli-cards-intro { padding-inline: 1rem; } .cli-card-desc { max-width: 36ch; } } + @media (min-width: 861px) and (min-height: 700px) { .cli-cards { position: absolute; left: 1rem; right: 1rem; bottom: 1.5rem; margin: 0; } } + @media (min-width: 861px) and (min-height: 700px) { body { overflow: clip; } } + .cli-card { display: flex; flex-direction: column; gap: 0.5rem; border: 1px solid var(--cli-border); border-radius: 1rem; padding: 1rem; text-align: left; background: var(--cli-bg); } + .cli-card-head { display: flex; align-items: center; } + .cli-card-title { margin-top: 0.25rem; font-size: 0.8125rem; line-height: 1.25rem; font-weight: 500; } .cli-card-icon { width: 14px; height: 14px; flex: none; color: var(--cli-fg-dim); } - .cli-card-desc { flex: 1; font-size: 12.5px; line-height: 1.45; color: var(--cli-fg-muted); } - .cli-card-code { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.25rem; padding: 0.45rem 0.35rem 0.45rem 0.75rem; border: 1px solid var(--cli-border); border-radius: 8px; background: var(--cli-code-bg); } - .cli-card-code code { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; letter-spacing: -0.02em; color: var(--cli-fg); user-select: text; } + .cli-card-desc { flex: 1; font-size: 0.8125rem; line-height: 1.25rem; color: var(--cli-fg-muted); } + .cli-card-code { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.75rem; padding: 0.35rem 0.35rem 0.35rem 0.75rem; border: 1px solid var(--cli-border); border-radius: 8px; background: var(--cli-code-bg); } + .cli-card-code code { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.78125rem; letter-spacing: -0.02em; color: var(--cli-fg); user-select: text; } .cli-prompt { color: var(--cli-fg-faint); user-select: none; } .cli-bin { color: var(--cli-syntax-mid); } .copy-btn { background: transparent; border: 0; width: 1.75rem; height: 1.75rem; cursor: pointer; color: var(--cli-fg-dim); border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; flex: none; transition: color 0.3s cubic-bezier(0.4,0.36,0,1), background 0.15s, transform 0.15s; } @@ -87,19 +122,15 @@ const PAGE_STYLE = ` `; function animatedText(text: string): string { - return ( - text - .split("") - .map((letter, i) => { - const delay = (i * 0.015).toFixed(3); - const char = letter === " " ? " " : escapeHtml(letter); - return `\ -${char}`; - }) - .join("") + - `${escapeHtml(text)}` - ); + // Split on words, not characters: the words stay real text for a screen + // reader, so the headline needs no duplicate hidden copy. + return text + .split(" ") + .map((word, i) => { + const delay = (0.15 + i * 0.14).toFixed(3); + return `${escapeHtml(word)}`; + }) + .join(" "); } const TERMINAL_ICON_SVG = ``; @@ -132,7 +163,8 @@ const COPY_SCRIPT = ` function commandCard(title: string, description: string, commandHtml: string): string { return `
-
${TERMINAL_ICON_SVG}${escapeHtml(title)}
+
${TERMINAL_ICON_SVG}
+

${escapeHtml(title)}

${escapeHtml(description)}

$ ${commandHtml} @@ -145,13 +177,21 @@ const SUCCESS_HTML = ` Clerk CLI +
- ${CLERK_LOGO} -

${animatedText("Authentication successful")}

-

You may close this window.

+
+
+ ${CLERK_LOGO} +

${animatedText("Authentication successful")}

+

You may close this window.

+
+
-

Set up, configure, and ship Clerk from your agent or terminal.

+
+

One CLI, from setup to production.

+

Install Clerk, configure it, and deploy from your agent or your terminal.

+
${commandCard( "Install", "Detects your framework and sets up API keys automatically.", @@ -179,9 +219,13 @@ const ERROR_HTML = (message: string) => ` Clerk CLI
- ${CLERK_LOGO} -

Authentication failed

-

${escapeHtml(message)}

+
+
+ ${CLERK_LOGO} +

Authentication failed

+

${escapeHtml(message)}

+
+
`;