Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea00011
chore: add magicast dependency for AST-based code manipulation
rafa-thayto Mar 17, 2026
74f88b3
refactor: fix framework SDK names and detection priority
rafa-thayto Mar 17, 2026
ce67a59
feat(init): add project context gathering
rafa-thayto Mar 17, 2026
c60cffd
feat(init): add scaffold system with framework-specific scaffolders
rafa-thayto Mar 17, 2026
1eedb83
feat(init): add scan, format, preview, and agent prompt modules
rafa-thayto Mar 17, 2026
9becf91
feat(init): rewrite init command with scaffold and scan flow
rafa-thayto Mar 17, 2026
1b4a8ac
docs(init): update README with scaffolding docs and framework table
rafa-thayto Mar 17, 2026
f24b49b
refactor(init): restructure agent prompts into markdown templates
rafa-thayto Mar 18, 2026
aede96f
refactor(init): make FileAction a discriminated union and extend Fram…
rafa-thayto Mar 19, 2026
d0d39e1
refactor(init): extract Next.js context enrichment to frameworks/next…
rafa-thayto Mar 19, 2026
1f8fc6d
refactor(init): replace scaffold key map with matches() dispatch and …
rafa-thayto Mar 19, 2026
953baaf
refactor(init): add shared helpers and flatten scaffoldNextjsMiddleware
rafa-thayto Mar 19, 2026
40b2443
refactor(init): update all scaffolders with skip actions, dep/matches…
rafa-thayto Mar 19, 2026
3a68466
refactor(init): remove findings cap, precompile regexes, and unexport…
rafa-thayto Mar 19, 2026
d484e38
refactor(init): replace readFileSync with static text imports for com…
rafa-thayto Mar 19, 2026
811a156
refactor(init): abstract formatter config into data-driven array
rafa-thayto Mar 19, 2026
3f814d4
test(init): update tests for discriminated union, enrichContext, and …
rafa-thayto Mar 19, 2026
55c8483
chore: update bun.lock with magicast dependency
rafa-thayto Mar 20, 2026
628343c
refactor(init): extract shared auth and config scaffolding helpers
rafa-thayto Mar 20, 2026
6f6e24c
refactor(init): use shared helpers in framework scaffolders
rafa-thayto Mar 20, 2026
75e1764
refactor(init): restructure preview, prompts, and scan modules
rafa-thayto Mar 20, 2026
9fa8f27
test(init): add framework scaffolder and scan tests
rafa-thayto Mar 20, 2026
ad51c64
chore(init): add markdown type declaration for static text imports
rafa-thayto Mar 20, 2026
f410e6a
feat(init): add framework lookup utility with aliases
rafa-thayto Mar 24, 2026
e2b96fd
feat(init): add i18nLocaleDir to ProjectContext type
rafa-thayto Mar 24, 2026
930e82a
refactor(init): extract previewPlan display function
rafa-thayto Mar 24, 2026
9938f0a
feat(init): add shared scaffolding helpers for auth, env, and i18n
rafa-thayto Mar 24, 2026
f956c0e
feat(init): detect i18n locale directory in Next.js context
rafa-thayto Mar 24, 2026
e1c0c2c
feat(init): support framework override in context gathering
rafa-thayto Mar 24, 2026
fca2e7c
feat(init): wire --framework, --yes, and --prompt CLI options
rafa-thayto Mar 24, 2026
0eeaf6d
refactor(init): migrate framework scaffolders to shared helpers
rafa-thayto Mar 24, 2026
ec1e31d
test(init): add i18n detection and locale routing tests
rafa-thayto Mar 24, 2026
ceeb037
docs(init): document new CLI options and update help output
rafa-thayto Mar 24, 2026
0d9e7f2
refactor(init): address PR review comments
rafa-thayto Mar 24, 2026
54a8e61
test(init): add missing framework scaffolder tests
rafa-thayto Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ Options:
-V, --version Display version
--mode <mode> Force interaction mode (human or agent).
Defaults to auto-detect based on TTY.
--verbose Show detailed error output
-h, --help Display help for command

Commands:
Expand All@@ -35,7 +36,9 @@ Commands:
deploy [options] Deploy your Clerk application (hidden)

clerk init
--framework <name> Framework to set up (skips auto-detection)
--prompt Output a prompt for an AI agent to integrate Clerk
--yes Skip confirmation prompts

clerk link
--app <id> Application ID to link (skips interactive picker)
Expand Down
13 changes: 13 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cli-core/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,7 @@
"@napi-rs/keyring": "^1.2.0",
"commander": "^14.0.3",
"env-paths": "^4.0.0",
"magicast": "^0.5.2",
"yaml": "^2.8.2"
}
}
8 changes: 7 additions & 1 deletion packages/cli-core/src/cli-program.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,13 @@ export function createProgram() {
}
});

program.command("init").description("Initialize Clerk in your project").action(init);
program
.command("init")
.description("Initialize Clerk in your project")
.option("--framework <name>", "Framework to set up (skips auto-detection)")
.option("--prompt", "Output a prompt for an AI agent to integrate Clerk")
.option("-y, --yes", "Skip confirmation prompts")
.action(init);

const auth = program.command("auth").description("Manage authentication");

Expand Down
145 changes: 123 additions & 22 deletions packages/cli-core/src/commands/init/README.md
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,140 @@
# Init Command

Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, and writing environment variables.
Initializes Clerk in a project by authenticating the user, linking a Clerk application, installing the SDK, pulling environment variables, and scaffolding framework-specific boilerplate.

## Usage

```sh
clerk init
clerk init --framework next
clerk init --prompt
clerk init -y
clerk init --yes
```

## Options

| Option | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--framework <name>` | Framework to set up (skips auto-detection). Valid values: `next`, `astro`, `nuxt`, `tanstack-start`, `react-router`, `vue`, `expo`, `react`, `express`, `fastify` |
| `--prompt` | Output a prompt for an AI agent to integrate Clerk, then exit |
| `-y, --yes` | Skip confirmation prompts |

## Agent Mode

When running in agent mode (`--mode agent` or non-TTY), outputs a framework-specific prompt with exact file paths and code snippets, then exits without modifying the project.

## Flow

1. Authenticates the user via `clerk auth login` (see [auth/README.md](../auth/README.md) for APIs)
2. Links the project to a Clerk application via `clerk link` (see [link/README.md](../link/README.md) for APIs)
3. Detects the project's framework from `package.json` and installs the appropriate Clerk SDK (e.g. `@clerk/nextjs` for Next.js)
4. Pulls development instance API keys via `clerk env pull` and writes them to `.env.local`
1. Gathers project context (framework, router variant, TypeScript, `src/` directory, package manager)
2. **Agent mode**: outputs a framework-specific prompt, then exits
3. **Human mode**: authenticates via `clerk auth login` (skipped if already authenticated)
4. Links the project via `clerk link` (skipped if already linked)
5. Displays detected framework and variant
6. Detects existing auth libraries (NextAuth, Auth0, Supabase, Firebase, Passport, Better Auth, Kinde) and shows migration guidance
7. Installs the appropriate Clerk SDK (skips if already present)
8. Pulls development instance API keys via `clerk env pull`
9. Generates a scaffold plan for the detected framework
10. Warns if the git working tree has uncommitted changes
11. Previews planned file changes and asks for confirmation
12. Writes scaffold files to disk
13. Runs project formatters (Prettier/Biome) on generated files
14. Scans for issues: hardcoded keys, leftover auth-library imports, stale API calls
15. Prints a summary of created, modified, and skipped files with recommendations

## Framework Detection

The command detects the project's framework by checking `package.json` dependencies:

| Dependency | Framework | Clerk SDK |
| ----------------------- | -------------- | ----------------------- |
| `next` | Next.js | `@clerk/nextjs` |
| `expo` | Expo | `@clerk/expo` |
| `astro` | Astro | `@clerk/astro` |
| `nuxt` | Nuxt | `@clerk/nuxt` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-start` |
| `react-router` | React Router | `@clerk/react-router` |
| `fastify` | Fastify | `@clerk/fastify` |
| `express` | Express | `@clerk/express` |
| `vue` | Vue | `@clerk/vue` |
| `react` | React | `@clerk/clerk-react` |
| `vite` | Vite | `@clerk/clerk-react` |

The package manager is detected from lock files (`bun.lockb` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm).
Detects the project's framework from `package.json` dependencies (checked top-to-bottom, first match wins):

| Dependency | Framework | Clerk SDK | Publishable Key Env Var |
| ----------------------- | -------------- | ----------------------------- | ----------------------------------- |
| `next` | Next.js | `@clerk/nextjs` | `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `astro` | Astro | `@clerk/astro` | `PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `nuxt` | Nuxt | `@clerk/nuxt` | `NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `@tanstack/react-start` | TanStack Start | `@clerk/tanstack-react-start` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `react-router` | React Router | `@clerk/react-router` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `vue` | Vue | `@clerk/vue` | `VITE_CLERK_PUBLISHABLE_KEY` |
| `expo` | Expo | `@clerk/expo` | `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` |
| `react` | React | `@clerk/react` | `VITE_CLERK_PUBLISHABLE_KEY` |
Comment thread
rafa-thayto marked this conversation as resolved.
| `express` | Express | `@clerk/express` | `CLERK_PUBLISHABLE_KEY` |
| `fastify` | Fastify | `@clerk/fastify` | `CLERK_PUBLISHABLE_KEY` |

Package manager is detected from lock files: `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, else npm.

## Scaffolding

Scaffolding is supported for the first 8 frameworks above. Expo, Express, and Fastify are detected (SDK is installed, env vars are pulled) but scaffolding is not yet supported — users are directed to the Clerk docs.

All scaffolding is idempotent — files are skipped if they already contain Clerk setup.

### Next.js (App Router)

| Action | File | Description |
| ------ | ------------------------------------- | ----------------------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| MODIFY | `app/layout.tsx` | Add `ClerkProvider` import and wrap `<body>` children |
| CREATE | `app/sign-in/[[...sign-in]]/page.tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `app/sign-up/[[...sign-up]]/page.tsx` | Sign-up page with `<SignUp />` component |

The middleware filename is version-aware: `proxy.ts` for Next.js 16+, `middleware.ts` for ≤15. Existing middleware files are preserved and composed with `clerkMiddleware`.

### Next.js (Pages Router)

| Action | File | Description |
| ------------- | ---------------------------------- | ---------------------------------------- |
| CREATE | `proxy.ts` or `middleware.ts` | `clerkMiddleware` with route protection |
| CREATE/MODIFY | `pages/_app.tsx` | `ClerkProvider` wrapping `<Component>` |
| CREATE | `pages/sign-in/[[...sign-in]].tsx` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up/[[...sign-up]].tsx` | Sign-up page with `<SignUp />` component |

### React / Vite

| Action | File | Description |
| ------ | ---------- | -------------------------------------------- |
| MODIFY | `main.tsx` | Add `ClerkProvider` import and wrap app root |

### React Router

| Action | File | Description |
| ------ | ------------------------ | ------------------------------------------------------ |
| MODIFY | `react-router.config.ts` | Enable `v8_middleware` future flag |
| MODIFY | `app/root.tsx` | Add ClerkProvider, clerkMiddleware, and rootAuthLoader |
| CREATE | `app/routes/sign-in.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `app/routes/sign-up.tsx` | Sign-up route with `<SignUp />` component |

### Nuxt

| Action | File | Description |
| ------ | ------------------- | ---------------------------------------- |
| MODIFY | `nuxt.config.ts` | Add `@clerk/nuxt` to modules array |
| CREATE | `pages/sign-in.vue` | Sign-in page with `<SignIn />` component |
| CREATE | `pages/sign-up.vue` | Sign-up page with `<SignUp />` component |

Nuxt's module system auto-configures middleware and auto-imports components.

### TanStack Start

| Action | File | Description |
| ------ | -------------------------- | ------------------------------------------- |
| MODIFY | `src/start.ts` | Add `clerkMiddleware` to request middleware |
| MODIFY | `src/routes/__root.tsx` | Add `ClerkProvider` and wrap body contents |
| CREATE | `src/routes/sign-in.$.tsx` | Sign-in route with `<SignIn />` component |
| CREATE | `src/routes/sign-up.$.tsx` | Sign-up route with `<SignUp />` component |

### Astro

| Action | File | Description |
| ------ | ------------------------- | ------------------------------------------- |
| MODIFY | `astro.config.mjs` | Add `clerk()` integration import and config |
| CREATE | `src/middleware.ts` | Clerk middleware with `onRequest` export |
| CREATE | `src/pages/sign-in.astro` | Sign-in page with `<SignIn />` component |
| CREATE | `src/pages/sign-up.astro` | Sign-up page with `<SignUp />` component |

### Vue

| Action | File | Description |
| ------ | --------- | -------------------------------------------------- |
| MODIFY | `main.ts` | Add `clerkPlugin` with `publishableKey` to Vue app |

## API Endpoints

Expand Down
Loading
Loading