Skip to content

feat: delegate keyless mode to SDK, autoclaim on authenticated init#267

Closed
rafa-thayto wants to merge 3 commits intomainfrom
keyless-bootstrap-keys
Closed

feat: delegate keyless mode to SDK, autoclaim on authenticated init#267
rafa-thayto wants to merge 3 commits intomainfrom
keyless-bootstrap-keys

Conversation

@rafa-thayto
Copy link
Copy Markdown
Contributor

Summary

  • Stop writing keys during keyless bootstrap: clerk init for unauthenticated users no longer calls createAccountlessApp() or writes temporary keys to .env.local. The @clerk/nextjs SDK handles keyless mode natively at runtime — when no keys are present, the SDK creates an accountless app and shows a "Configure your application" widget.

  • Read SDK breadcrumbs: The CLI now reads the SDK's keyless breadcrumb at .clerk/.tmp/keyless.json (in addition to the legacy CLI breadcrumb at .clerk/keyless.json). A unified readAnyKeylessBreadcrumb() reader tries the SDK path first and normalizes both formats to { claimToken, source }.

  • Autoclaim during clerk init: When an authenticated user runs clerk init without --app, the CLI checks for an SDK keyless breadcrumb before falling through to authenticateAndLink. If found, it claims the temporary app, links it, and pulls real keys — all in one step.

Test plan

  • bun run typecheck passes
  • bun run lint passes
  • bun run format:check passes
  • bun test packages/cli-core/src/lib/keyless.test.ts — 28 tests pass (17 new SDK breadcrumb + unified reader tests)
  • bun test packages/cli-core/src/lib/autoclaim.test.ts — 11 tests pass (updated for dual breadcrumb clearing)
  • bun test packages/cli-core/src/commands/init/index.test.ts — 46 tests pass (5 new autoclaim-in-init tests)
  • Manual E2E: run clerk init --starter --framework next --yes unauthenticated → app scaffolds without keys → run the app → SDK enters keyless mode and writes .clerk/.tmp/keyless.json → authenticate with clerk auth login → re-run clerk init → autoclaim kicks in, real keys are pulled

…crumb on init

clerk init no longer calls createAccountlessApp() for unauthenticated users —
the SDK handles keyless mode natively at runtime. When an authenticated user
re-runs clerk init (without --app), the CLI reads the SDK's breadcrumb at
.clerk/.tmp/keyless.json, claims the temporary app, links it, and pulls real
keys — eliminating the need for a separate clerk auth login step.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 7, 2026

🦋 Changeset detected

Latest commit: 14050ca

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
clerk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

Warning

Rate limit exceeded

@rafa-thayto has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 41 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ca4fb98b-9713-45fb-bfd9-d258281a0ced

📥 Commits

Reviewing files that changed from the base of the PR and between 9eb1eb2 and 14050ca.

📒 Files selected for processing (3)
  • .changeset/keyless-bootstrap-keys.md
  • packages/cli-core/src/commands/init/index.test.ts
  • packages/cli-core/src/commands/init/index.ts
📝 Walkthrough

Walkthrough

This PR extends the Clerk CLI's keyless authentication flow to support breadcrumbs created by the Clerk SDK at .clerk/.tmp/keyless.json alongside the existing CLI breadcrumb at .clerk/keyless.json. A new unified breadcrumb reader checks the SDK location first and falls back to the CLI location. The init command now attempts to claim and link the temporary keyless app automatically before prompting for manual authentication, and it skips interactive app selection when autoclaim succeeds. The change is reflected across the keyless/autoclaim libraries, integration with the init command, and comprehensive test coverage for both sources and various claim outcomes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 accurately and concisely summarizes the main changes: delegating keyless mode to SDK and adding autoclaim on authenticated init.
Description check ✅ Passed The description is well-organized and directly related to the changeset, covering the three key objectives: stopping key writing in keyless bootstrap, reading SDK breadcrumbs, and autoclaiming during init.
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.


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

@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: 1

🤖 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 `@packages/cli-core/src/commands/init/index.ts`:
- Around line 104-116: tryInitAutoclaim currently returns a result object but
the code treats any status === "claimed" as fully done; change the flow to
inspect the full result from tryInitAutoclaim/attemptAutoclaim and only skip
authenticateAndLink()/pull() when result.status === "claimed" AND
result.envPulled === true (set autoclaimPulled = true only in that case); if
envPulled is false (or missing) treat it as not fully claimed and proceed to
call authenticateAndLink(ctx.cwd, ...) and later pull() so local linking/envs
are completed; apply the same adjustment to the other tryInitAutoclaim usage
sites (the other blocks that currently set autoclaimPulled on any "claimed"
result).
🪄 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

Run ID: 5138e676-8dc0-4ef2-a35a-51c16ece8551

📥 Commits

Reviewing files that changed from the base of the PR and between aca3db2 and 9eb1eb2.

📒 Files selected for processing (8)
  • packages/cli-core/src/commands/auth/README.md
  • packages/cli-core/src/commands/init/README.md
  • packages/cli-core/src/commands/init/index.test.ts
  • packages/cli-core/src/commands/init/index.ts
  • packages/cli-core/src/lib/autoclaim.test.ts
  • packages/cli-core/src/lib/autoclaim.ts
  • packages/cli-core/src/lib/keyless.test.ts
  • packages/cli-core/src/lib/keyless.ts

Comment on lines +104 to +116
let autoclaimPulled = false;
if (!keyless && !manualSetup) {
bar();
const createIfMissing = agent
? await deriveProjectName(ctx.cwd, bootstrap?.projectName)
: undefined;
await authenticateAndLink(ctx.cwd, options.app, createIfMissing);

const claimed = !options.app && authed && (await tryInitAutoclaim(ctx.cwd));
if (!claimed) {
const createIfMissing = agent
? await deriveProjectName(ctx.cwd, bootstrap?.projectName)
: undefined;
await authenticateAndLink(ctx.cwd, options.app, createIfMissing);
} else {
autoclaimPulled = true;
}
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 | 🟠 Major | ⚡ Quick win

Handle partial autoclaim success before skipping normal link/env pull

tryInitAutoclaim treats every status: "claimed" as fully complete, but attemptAutoclaim can return { status: "claimed", envPulled: false } when local linking or env pull failed. The current flow then skips both authenticateAndLink() and the later pull(), which can leave the project not fully configured.

Suggested fix
-  let autoclaimPulled = false;
+  let autoclaimPulled = false;
   if (!keyless && !manualSetup) {
     bar();

-    const claimed = !options.app && authed && (await tryInitAutoclaim(ctx.cwd));
-    if (!claimed) {
+    const autoclaim = !options.app && authed ? await tryInitAutoclaim(ctx.cwd) : { claimed: false, envPulled: false };
+    autoclaimPulled = autoclaim.envPulled;
+    if (!autoclaim.claimed || !autoclaim.envPulled) {
       const createIfMissing = agent
         ? await deriveProjectName(ctx.cwd, bootstrap?.projectName)
         : undefined;
       await authenticateAndLink(ctx.cwd, options.app, createIfMissing);
-    } else {
-      autoclaimPulled = true;
     }
   }
-async function tryInitAutoclaim(cwd: string): Promise<boolean> {
+async function tryInitAutoclaim(
+  cwd: string,
+): Promise<{ claimed: boolean; envPulled: boolean }> {
   const result = await attemptAutoclaim(cwd);
   if (result.status === "claimed") {
     const label = result.app.name || result.app.application_id;
-    log.success(`Claimed and linked \`${label}\``);
-    return true;
+    if (result.envPulled) {
+      log.success(`Claimed and linked \`${label}\``);
+    } else {
+      log.warn(`Claimed \`${label}\`, but local setup was incomplete; continuing setup.`);
+    }
+    return { claimed: true, envPulled: result.envPulled };
   }
   if (result.status !== "not_keyless") {
     log.debug(`init: autoclaim returned '${result.status}', falling through to link`);
   }
-  return false;
+  return { claimed: false, envPulled: false };
 }

Also applies to: 138-139, 322-333

🤖 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/cli-core/src/commands/init/index.ts` around lines 104 - 116,
tryInitAutoclaim currently returns a result object but the code treats any
status === "claimed" as fully done; change the flow to inspect the full result
from tryInitAutoclaim/attemptAutoclaim and only skip
authenticateAndLink()/pull() when result.status === "claimed" AND
result.envPulled === true (set autoclaimPulled = true only in that case); if
envPulled is false (or missing) treat it as not fully claimed and proceed to
call authenticateAndLink(ctx.cwd, ...) and later pull() so local linking/envs
are completed; apply the same adjustment to the other tryInitAutoclaim usage
sites (the other blocks that currently set autoclaimPulled on any "claimed"
result).

When `attemptAutoclaim` returns `{ status: "claimed", envPulled: false }`
(claim succeeded but local linking or env pull failed), `tryInitAutoclaim`
was returning `true`, causing the caller to set `autoclaimPulled = true`
and skip the fallback `env pull`. This left users without a `.env.local`
file despite a successful claim.

Now `tryInitAutoclaim` propagates the `envPulled` flag so the caller
retries `env pull` when autoclaim's internal pull failed.
@rafa-thayto rafa-thayto closed this May 8, 2026
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