-
Notifications
You must be signed in to change notification settings - Fork 454
feat(repo): add clerk-monorepo Claude Code skill #8769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jacekradko
wants to merge
5
commits into
main
Choose a base branch
from
jacek/clerk-monorepo-skill
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
853b7c5
feat(repo): add clerk-monorepo Claude Code skill
jacekradko fd3f7f8
fix(repo): correct @clerk/ui location and break-check framing in skill
jacekradko cc826e1
fix(repo): correct stale and inaccurate claims in clerk-monorepo skill
jacekradko 75d8cf0
Merge branch 'main' into jacek/clerk-monorepo-skill
jacekradko ade1868
docs(repo): explain how the clerk-monorepo skill activates and is mai…
jacekradko File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| --- | ||
| --- |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # Claude Code skills | ||
|
|
||
| This directory holds [Claude Code skills](https://code.claude.com/docs/en/skills) that ship with the | ||
| repo. Skills are how-to playbooks the agent loads on demand. They complement `AGENTS.md` (the | ||
| canonical rules, read automatically by most coding agents) with step-by-step recipes. | ||
|
|
||
| ## How a skill is activated | ||
|
|
||
| There is nothing to install or enable. Anyone who checks out this repo and runs Claude Code in it | ||
| gets every skill in this directory automatically: | ||
|
|
||
| 1. At session start, Claude only sees each skill's frontmatter `description`. This costs almost no | ||
| context. | ||
| 2. When a request matches that description (for `clerk-monorepo`: setting up the repo, building or | ||
| testing a package, changesets, commit conventions, breaking-change questions), Claude loads the | ||
| full `SKILL.md` body on its own. | ||
| 3. You can also invoke a skill explicitly by typing `/clerk-monorepo` in the prompt. `/skills` lists | ||
| everything available. | ||
| 4. Files under `references/` are read only when the loaded skill points at them, so deep-dive | ||
| content stays out of context until it is needed. | ||
|
|
||
| Edits to a `SKILL.md` take effect immediately, including in already-running sessions. | ||
|
|
||
| ## Scope | ||
|
|
||
| Skills are Claude Code specific. Cursor does not read this directory; it uses `.cursor/rules/` and | ||
| `AGENTS.md`. When a repo rule changes, update `AGENTS.md` first, then mirror the change here and in | ||
| `.cursor/rules/` where relevant. | ||
|
|
||
| ## Maintaining a skill | ||
|
|
||
| - `AGENTS.md` is the authority. If a skill disagrees with it, fix the skill. | ||
| - Keep `SKILL.md` lean; the whole body enters context when the skill triggers. Push detail into | ||
| `references/*.md`, which load on demand. | ||
| - Write the frontmatter `description` as the trigger: it is the only part the model sees up front, | ||
| so it should say _when_ to use the skill, not just what it contains. | ||
| - Skills contain factual claims about the repo (scripts, package lists, CI behavior). When you | ||
| rename a script, add a package, or change a workflow, grep this directory for stale mentions. | ||
| - `pnpm format` does not cover `.claude/`. Format skill files with | ||
| `pnpm prettier --write '.claude/**/*.md'`. | ||
|
|
||
| ## Skills in this repo | ||
|
|
||
| | Skill | Use it for | | ||
| | ---------------- | ---------------------------------------------------------------------------------------------------------------------------- | | ||
| | `clerk-monorepo` | Day-to-day work in the monorepo: setup, build/test loops, the package map, changesets, commits, PRs, breaking-change checks. | | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| --- | ||
| name: clerk-monorepo | ||
| description: >- | ||
| Work effectively in the clerk/javascript SDK monorepo. Use when setting up the repo, | ||
| building / testing / running a package, deciding which of the @clerk/* packages to | ||
| change, writing changesets, conventional commits, or PRs, or checking whether a change | ||
| is a breaking change to clerk-js or ui. Covers the pnpm + turbo dev loop, the package | ||
| map, and the repo's hard rules. AGENTS.md is the authority on the rules; this skill is | ||
| the how-to layer that points back to it. | ||
| --- | ||
|
|
||
| # Working in the clerk/javascript monorepo | ||
|
|
||
| This is Clerk's JavaScript SDK monorepo: 23 packages (20 published `@clerk/*` plus the private | ||
| `@clerk/msw`, `@clerk/headless`, and `@clerk/swingset`) managed with pnpm | ||
| workspaces and Turborepo. Read this before building, testing, committing, or touching anything | ||
| under `packages/`. | ||
|
|
||
| `AGENTS.md` (repo root) is the canonical source of truth for the hard rules. This skill restates | ||
| those rules in actionable form and links back to it. If a rule here ever disagrees with `AGENTS.md`, | ||
| `AGENTS.md` wins, and the discrepancy should be fixed here. | ||
|
|
||
| ## Fast setup (happy path) | ||
|
|
||
| The order matters more than the commands. Do them in sequence: | ||
|
|
||
| 1. **Node `>=24.15.0`** (pinned in `.nvmrc`). `nvm use` if you have nvm. Wrong Node version is the | ||
| single most common cause of cryptic "cannot find module @clerk/..." build errors. | ||
| 2. **`corepack enable`** before installing. The `preinstall` hook runs `only-allow pnpm`; npm/yarn | ||
| are hard-blocked. Corepack pins the right pnpm (`>=10.33.0`). | ||
| 3. **`pnpm install` from the repo root** (never a subdirectory). It is a workspace; installing from | ||
| a package dir leaves cross-package links broken. | ||
| 4. **`pnpm build`** before anything else. Packages depend on each other's built `dist/` + `.d.ts`. | ||
| Skipping this makes `dev`, tests, and the editor's types all report phantom errors. | ||
| 5. **`pnpm dev`** to start watch mode. | ||
|
|
||
| Full sequence, the 11 footguns, and the internal integration-test / 1Password setup live in | ||
| [`references/setup-and-footguns.md`](references/setup-and-footguns.md). | ||
|
|
||
| ## Package map: where does X live? | ||
|
|
||
| The ~10 packages people touch most. Full 23-package table, the dependency pyramid, and the complete | ||
| "change X, touch Y" routing are in [`references/package-map.md`](references/package-map.md). | ||
|
|
||
| | Package | You change it when... | | ||
| | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `@clerk/shared` | Utilities used everywhere (storage, events, React helpers). Most-depended-on; changes fan out to ~20 packages. Types live here too (`@clerk/shared/types`). | | ||
| | `@clerk/backend` | Server-side: JWT verification, the Backend API REST client, webhooks. Used by every framework adapter. | | ||
| | `@clerk/clerk-js` | ⚠️ The browser runtime loaded via script tag. **Backwards-compat sensitive** (see rules). | | ||
| | `@clerk/ui` | ⚠️ The React components powering the hosted sign-in / sign-up UI. **Backwards-compat sensitive**. | | ||
| | `@clerk/react` | Shared React hooks/context (`useAuth`, `useUser`, ...) consumed by the React-based adapters. | | ||
| | `@clerk/nextjs` | Next.js SDK: middleware, route handlers, server components. | | ||
| | `@clerk/express` | Express middleware and server helpers. | | ||
| | `@clerk/expo` | React Native / Expo SDK. | | ||
| | `@clerk/localizations` | UI translation strings (consumed by `ui`). | | ||
| | `@clerk/testing` | E2E helpers for consumers (Playwright / Cypress). | | ||
|
|
||
| > Heads-up: `packages/` may contain stale leftover dirs (`types`, `remix`, `themes`, `elements`, ...) | ||
| > with only build artifacts and no `package.json`. Those are removed packages, not active ones. The | ||
| > authoritative list is the git-tracked `packages/*/package.json` files. | ||
|
|
||
| ## Dev-loop recipes | ||
|
|
||
| ```bash | ||
| # Build one package (and its deps, via turbo ^build) | ||
| pnpm turbo build --filter=@clerk/nextjs | ||
|
|
||
| # Watch subsets instead of everything | ||
| pnpm dev:fe-libs # clerk-js + ui + shared | ||
| pnpm dev:js # clerk-js only | ||
| pnpm dev:sandbox # rspack sandbox for previewing UI components | ||
|
|
||
| # Run one package's unit tests (builds the package and its deps first) | ||
| pnpm turbo test --filter=@clerk/backend | ||
| # Faster, after a full build, for tight iteration: | ||
| pnpm --filter @clerk/backend test | ||
|
|
||
| # Run a single test file (vitest matches by filename substring). No `--` before the path: | ||
| # pnpm forwards a literal `--` into the script and vitest then ignores the filter. | ||
| pnpm --filter @clerk/shared test path/to/file.test.ts | ||
| # @clerk/backend runs a multi-runtime suite (run-s), so target one runtime for a single file: | ||
| pnpm --filter @clerk/backend test:node path/to/file.test.ts | ||
|
|
||
| # Quality gates (CI runs these) | ||
| pnpm lint | ||
| pnpm format # workspace packages plus root files, docs/, integration/, scripts/ | ||
| pnpm prettier --write '.claude/**/*.md' # pnpm format does not cover .claude/; format skill files this way | ||
|
|
||
| # Changesets | ||
| pnpm changeset # for package-affecting changes | ||
| pnpm changeset:empty # for repo/tooling-only changes (see rules) | ||
| ``` | ||
|
|
||
| Test runner differs by package (`shared`, `clerk-js`, most adapters use vitest; `backend` runs a | ||
| multi-runtime suite), but the `pnpm --filter <name> test` invocation is uniform. | ||
|
|
||
| If the editor or a build reports stale types from `@clerk/shared`, rebuild the foundations: | ||
| `pnpm turbo build --filter=@clerk/shared`. | ||
|
|
||
| Integration-test variants (`pnpm test:integration:*`) and canary/snapshot releases are the long tail: | ||
| see [`references/setup-and-footguns.md`](references/setup-and-footguns.md) and `docs/CONTRIBUTING.md`. | ||
|
|
||
| ## The hard rules | ||
|
|
||
| Each rule below restates `AGENTS.md`; the parenthetical is how it is enforced. | ||
|
|
||
| - **pnpm only, Node `>=24.15`, pnpm `>=10.33`.** (`preinstall` blocks npm/yarn; `engines` in | ||
| `package.json`.) | ||
| - **Every PR needs a changeset.** Use `pnpm changeset` for anything that affects a published package. | ||
| Use `pnpm changeset:empty` for repo/tooling-only changes; an empty changeset is **two `---` | ||
| delimiters with no body** (local `CLAUDE.local.md` convention). A changeset is a changelog entry | ||
| for users upgrading, not a summary of the diff. (CI fails PRs missing a changeset.) | ||
| - **Conventional commit `type(scope):`, scope is mandatory.** Enforced on the **PR title** | ||
| (`.github/workflows/pr-title-linter.yml`), not on individual commits. There is no local | ||
| `commit-msg` hook. Valid `scope` = any `packages/*` short name **and** its `clerk-`-stripped form | ||
| (so `clerk-js` accepts `clerk-js` or `js`), plus `repo`, `release`, `e2e`, `ci`, `*`. `docs` is a | ||
| valid **type**, not a scope. Source of truth: `commitlint.config.ts`. | ||
| - **`clerk-js` and `ui` must stay backwards-compatible across non-major releases.** A new `clerk-js` | ||
| runtime loads into apps still pinned to an _older_ framework SDK (`@clerk/nextjs`, etc.), so | ||
| removing or renaming anything an older SDK calls breaks those apps in production. (`break-check` | ||
| flags API-surface changes in `api-changes.yml`, but that check is informational; shipping such a | ||
| change means a `major`, gated by `major-version-check.yml`.) | ||
| - **Changes to the core `Clerk` class API (`packages/clerk-js/src/core/clerk.ts`) require a major | ||
| version** and `!allow-major` approval. (`.github/workflows/major-version-check.yml`.) APIs prefixed | ||
| `__internal_` or exported from an `/experimental` subpath are exempt from SemVer guarantees. | ||
|
|
||
| ## PR / changeset / commit flow | ||
|
|
||
| 1. Branch off `main`. | ||
| 2. Make the change in the right package(s); add/update unit tests next to the code. | ||
| 3. `pnpm changeset` (or `pnpm changeset:empty`). | ||
| 4. Verify locally: `pnpm build`, `pnpm test` (or the filtered forms above), `pnpm lint`, | ||
| `pnpm format:check`. | ||
| 5. Open the PR; the title must be a valid conventional commit (it becomes the squash commit). Fill in | ||
| the PR template. | ||
|
|
||
| Release _policy_ (when/how things ship, canary, snapshot, backports) is in `docs/PUBLISH.md`. This | ||
| skill stops at opening the PR. | ||
|
|
||
| ## Breaking-change quick check | ||
|
|
||
| If you are editing `clerk-js` or `ui`, answer these. **Any "yes" means it is breaking**, needs a | ||
| major + `!allow-major`, and `break-check` will flag it: | ||
|
|
||
| 1. Removing or renaming a public export, method, or property? | ||
| 2. Changing a public function/method signature (new required arg, changed return type)? | ||
| 3. Changing the `Clerk` class public surface in `core/clerk.ts`? | ||
| 4. Renaming/removing something an older SDK version still calls at runtime? | ||
|
|
||
| If the symbol is `__internal_`/`__experimental_`-prefixed or under `/experimental`, it is exempt. | ||
| Full decision matrix: | ||
| [`references/breaking-changes.md`](references/breaking-changes.md). | ||
|
|
||
| ## Deeper references | ||
|
|
||
| - `AGENTS.md`: the canonical hard rules (authority for this skill). | ||
| - `docs/CONTRIBUTING.md`: full setup, testing, JSDoc/Typedoc, changeset writing. | ||
| - `docs/PUBLISH.md`: release process (stable, canary, snapshot, backport, `!allow-major`). | ||
| - `docs/CICD.md`: CI/CD pipeline and automated releases. | ||
| - `docs/SECURITY.md`: vulnerability reporting (do **not** open public issues). | ||
| - `references/theming-architecture.md`: deep dive on the `@clerk/ui` appearance/theming system. | ||
| - Bundled: [`setup-and-footguns.md`](references/setup-and-footguns.md), | ||
| [`package-map.md`](references/package-map.md), | ||
| [`breaking-changes.md`](references/breaking-changes.md). | ||
|
|
||
| For analyzing or coordinating a **release PR** (the "Version packages" PR), use the dedicated | ||
| `analyze-javascript-release` and `coordinate-clerk-release` skills, not this one. |
79 changes: 79 additions & 0 deletions
79
.claude/skills/clerk-monorepo/references/breaking-changes.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # Breaking changes | ||
|
|
||
| Why `clerk-js` and `ui` carry a stricter contract than the rest of the monorepo, how to tell if a | ||
| change is breaking, and what CI does about it. `AGENTS.md` is the authority; this expands on it. | ||
|
|
||
| ## Why `clerk-js` and `ui` are special | ||
|
|
||
| Most packages follow ordinary SemVer: consumers pin a version and upgrade deliberately. `clerk-js` | ||
| is different. Its **non-major releases are pushed to consuming apps without those apps updating any | ||
| dependency**. A browser loads the latest `clerk-js` runtime even when the app is still pinned to an | ||
| older framework SDK (`@clerk/nextjs`, `@clerk/react`, etc.). `AGENTS.md` puts `ui` under the same | ||
| contract: its compiled runtime reaches apps the same way, without a version bump. (`clerk-js` does | ||
| not declare `@clerk/ui` as a package dependency; `@clerk/ui` is a workspace dep of the framework | ||
| adapters, e.g. `react`/`astro`/`vue`/`chrome-extension`. The constraint is about the delivered | ||
| runtime, not the dependency graph.) | ||
|
|
||
| Consequence: a new `clerk-js`/`ui` runtime must keep working for **every SDK version still in the | ||
| wild**, not just the current monorepo state. Removing or renaming anything an older SDK calls at | ||
| runtime breaks those apps in production. This is the single most important constraint when editing | ||
| these two packages. | ||
|
|
||
| ## The `Clerk` class API contract | ||
|
|
||
| `packages/clerk-js/src/core/clerk.ts` defines the public `Clerk` class. Its public surface (methods, | ||
| properties, constructor, static members like `Clerk.version`) is a contract depended on by internal | ||
| and external consumers, including older SDKs loading the latest runtime. **Changes to it require a | ||
| major version.** Treat it as frozen unless you are doing a deliberate major. | ||
|
|
||
| ## Is my change breaking? Decision matrix | ||
|
|
||
| For a change in `clerk-js` or `ui`, any "yes" makes it breaking: | ||
|
|
||
| 1. **Remove or rename** a public export, method, or property. | ||
| 2. **Change a signature**: add a required parameter, change a parameter's type, or change a return | ||
| type of a public function/method. | ||
| 3. **Change the `Clerk` class public surface** in `core/clerk.ts` (any of the above on it). | ||
| 4. **Change runtime behavior an older SDK relies on**: rename an event, change a thrown error's | ||
| shape, alter the meaning of an existing option. | ||
|
|
||
| Not breaking (safe in a minor/patch): | ||
|
|
||
| - Adding a new optional parameter, method, property, or export. | ||
| - Internal refactors with no change to the public surface. | ||
| - Changes to anything prefixed `__internal_` or `__experimental_`. | ||
| - Changes to anything exported from an `/experimental` subpath (explicitly outside SemVer). | ||
|
|
||
| When unsure, assume breaking and check with the team. Cheaper than a production regression in apps | ||
| you cannot redeploy. | ||
|
|
||
| ## Internal and experimental escape hatches | ||
|
|
||
| If you need to ship something that is not yet stable: | ||
|
|
||
| - Prefix methods/properties with `__internal_` (or `__experimental_` for experimental additions to | ||
| existing APIs) to signal "no SemVer guarantee." | ||
| - Or export from an `/experimental` subpath. | ||
|
|
||
| Both are documented in `docs/CONTRIBUTING.md` (the "Experimental and internal APIs" section) and are | ||
| exempt from the breaking-change rules above. | ||
|
|
||
| ## What CI enforces | ||
|
|
||
| - **`break-check`** (`.github/workflows/api-changes.yml`) diffs the public API surface | ||
| (`.d.ts` declarations) and flags removals, renames, and signature changes. Treat it as a signal, | ||
| not a gate: the job runs `continue-on-error`, and an AI reviewer (`ai.applyDowngrades` in | ||
| `break-check.config.json`) can reclassify findings, so it is informational. Still investigate | ||
| anything it flags rather than assuming a false positive. | ||
| - **Major Version Check** (`.github/workflows/major-version-check.yml`) is the gate for a major: a | ||
| `major` changeset bump fails the check until a public org member comments `!allow-major`. (It is | ||
| not yet in `main`'s required-checks list, so treat a red check as blocking even when the merge | ||
| button is not.) The exact comment commands (`!allow-major`, `!snapshot`, `!preview`) and when to | ||
| use each are in `docs/PUBLISH.md`. | ||
|
|
||
| ## If a breaking change is genuinely required | ||
|
|
||
| 1. Confirm it truly cannot be done additively (new optional API, deprecate-then-remove later). | ||
| 2. Discuss with the team; major releases are coordinated, not casual. | ||
| 3. Write a changeset with a `major` bump and a clear migration path for consumers. | ||
| 4. Expect the `!allow-major` approval step. See `docs/PUBLISH.md`. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: clerk/javascript
Length of output: 2967
🌐 Web query:
Claude CodeSKILL.mdedits take effect already-running session re-read invoked skill content stays in session💡 Result:
Claude Code features live change detection for SKILL.md files, which allows edits to take effect in an already-running session without requiring a full restart [1][2][3]. However, once a skill is invoked, its content is injected into the session as a single message and remains there for the duration of that session [1][2][3]. Claude Code does not re-read or refresh the SKILL.md file on subsequent turns within the same session after it has already been invoked [1][2][3]. Consequently, if you edit a SKILL.md file after having already triggered the skill during your current session, Claude will continue to use the version of the instructions it loaded during the initial invocation [1][3]. To ensure Claude uses the updated instructions, you must either start a new session or be aware that the changes will only apply if the skill is triggered for the first time after the file has been edited [1][2][3]. For changes to plugin-based skill components—such as hooks,.mcp.json, agents, or output-styles—you must use the /reload-plugins command to apply updates [1][2][3].
Citations:
Clarify when
SKILL.mdedits apply during an active session..claude/skills/README.mdline 22 claims edits apply immediately in already-running sessions, but Claude Code keeps the already-invoked skill instructions loaded for the session and doesn’t refresh theSKILL.mdon subsequent turns; updates take effect after re-invoking the skill (or starting a new session).🔧 Suggested wording
📝 Committable suggestion
🤖 Prompt for AI Agents