clerk/migrate-branch-to-clerk
Run and troubleshoot scripts/migrate-clerk-docs-to-clerk.ts, which migrates a clerk-docs feature branch (and its PR) into the clerk/clerk monorepo under clerk-docs/. Use when the user asks to migrate a branch or PR to clerk, re-run a migration, or hit a migration conflict, merge conflict, or "conflict-synced-to-docs" error from the script.
npx skills add https://github.com/clerk/clerk-docs --skill migrate-branch-to-clerk
scripts/migrate-clerk-docs-to-clerk.ts moves the current clerk-docs feature branch into the clerk/clerk monorepo: it rewrites the branch's history under clerk-docs/ (git-filter-repo), cherry-picks only the branch's own commits onto the clerk base, pushes a migration branch, opens a clerk PR mirroring the source PR (title, body, draft state, assignees, reviewers), backlinks and closes the source clerk-docs PR.
Run from the clerk-docs repo root, on the feature branch to migrate (never main unless doing a deliberate full-history import with --allow-docs-main):
pnpm migrate:clerk [options] # = tsx scripts/migrate-clerk-docs-to-clerk.ts
Preconditions the script enforces (don't pre-check manually; it fails fast with hints):
git, gh (authenticated), and git-filter-repo installed at minimum versionsclerk/clerk, read + comment access to clerk/clerk-docsCommon forms:
# Standard migration (clones clerk to a temp dir — slow but zero-setup)
pnpm migrate:clerk
# Use an existing local clerk checkout (faster; preferred when a conflict is likely)
pnpm migrate:clerk --clerk-path ../clerk
# Preview without any git/GitHub writes (read-only gh calls still run)
pnpm migrate:clerk --dry-run
# Several open PRs for the branch → must disambiguate
pnpm migrate:clerk --pr 1234
# Build the branch locally in the clerk workspace but skip push/PR (requires --clerk-path)
pnpm migrate:clerk --clerk-path ../clerk --local-only
Other flags: --target-branch (clerk-side branch name; default <docs-branch>-docs-migration), --clerk-base (default main), --no-merge-main (skip the pre-migration merge of docs origin/main), --no-close-source-pr, --allow-dirty-docs, --debug. Run --help for the full list.
The script is idempotent per branch. On each run it looks for the migration branch in clerk:
main), push, open PR.git cherry, plus a fingerprint filter — author email + timestamp + subject — that recognizes commits whose patch changed due to a prior conflict resolution, so nothing is ever re-picked into the same conflict).--target-branch.So the normal workflow for "the docs PR got new commits" is simply: re-run the script.
Conflicts escalate through three tiers automatically. Match the script's output to the tier:
Tier 1 — auto-resolved (no action). Log lines like Auto-resolved a conflicted delta commit to the docs branch final state. Safe by construction: it only fires when the clerk side of every conflicted file is a state the docs branch history already contains, so the PR's net diff cannot change.
Tier 2 — conflict-synced-to-docs error (resolve here, in clerk-docs). Clerk had its own edits to a conflicted file. The script has already:
chore(migration): record clerk's state... commit), and<<<<<<< conflict markers into the docs working tree, then cleaned up the clerk side.Do this:
package-lock.json) are skipped and never listed — there is nothing to resolve, and the re-run auto-resolves them on its own.record clerk's state commit — never drop, squash away, or amend it. It anchors clerk's version in docs history; the re-run's auto-resolution depends on it.Tier 3 — create-merge-conflict / update-merge-conflict error (resolve in the clerk workspace). Last resort, only when the conflict can't be represented docs-side (path outside clerk-docs/, a binary conflicted file, or the docs repo was dirty/on the wrong branch). The clerk workspace is left conflicted with the filter-repo remote preserved; follow the printed hints — resolve there, push manually (upstream is pre-configured so plain git push targets the migration branch), or git cherry-pick --abort / git merge --abort and re-run.
--no-merges); their content arrives via the base merge or auto-resolution instead.skippedEmpty > 0) is normal: auto-resolving one commit to the final file state can make later picks empty.--dry-run makes zero writes anywhere — including no sync-back commits to the docs repo — but still calls gh read-only.$TMPDIR: clerk-migrate-* (the temp clerk clone) and clerk-docs-migrate-* (the filter-repo duplicate). After a tier-2 error both are safe to delete. After a tier-3 error the conflicted workspace and duplicate are preserved _on purpose_ until the conflict is dealt with.--local-only without --clerk-path is rejected: the branch would only exist in a temp clone that gets deleted.Tests live in scripts/migrate-clerk-docs-to-clerk.test.ts (vitest; includes integration tests that build real git repos in $TMPDIR and a multi-run end-to-end lifecycle test). Run them after any change:
pnpm vitest run scripts/migrate-clerk-docs-to-clerk.test.ts
Take clerk/migrate-branch-to-clerk from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.