posthog/porting-code-prs
> Recreate open PostHog/code pull requests as PostHog/posthog PRs against the imported products/desktop/ tree, preserving commit authorship. Use when asked to port, remake, migrate or recreate PostHog/code PRs onto the monorepo after the desktop import, whether a single PR or a sweep of everything an author has open. Covers enumerating an author's open PRs, applying the patch series with git am --directory, the 3-way fallback via fetching the source PR head, the paths that must never be blind-applied (.github workflows, lockfiles, drift-listed local patches), verification from products/desktop/ code repo PRs, desktop migration, port my PRs, remake PRs onto the monorepo.
npx skills add https://github.com/PostHog/posthog --skill porting-code-prs
PostHog/code's main is frozen after the desktop import.
The tree lives at products/desktop/ as a verbatim copy of the source at a pinned SHA, so open PRs on PostHog/code can no longer land there and are remade as monorepo PRs instead.
products/desktop/MIGRATION.md is the contract for the import: its pinned SHA, drift list and workflow mapping table are authoritative over anything restated here. Read it before resolving any conflict.
Path mapping: <path> in PostHog/code becomes products/desktop/<path>.
The one exception is .github/, which was not imported: source workflows were transformed into root .github/workflows/desktop-*.yml files per the mapping table and transform rules in MIGRATION.md.
Resolve the author's GitHub login first (gh api user --jq .login when it is the requester). Then enumerate:
gh pr list --repo PostHog/code --author <login> --state open \
--json number,title,isDraft,headRefName,url,body
For each PR decide: port, skip or flag.
products/desktop/ (superseded, or landed upstream and arrived via a resync). Check the tree, not just the PR state.The skill works the same for a single PR; the sweep is just the loop.
Work on a branch off fresh master, one monorepo PR per source PR. Reusing the source head branch name keeps the pair easy to correlate.
PATCH=$(mktemp)
gh pr diff <N> --repo PostHog/code --patch > "$PATCH"
git fetch https://github.com/PostHog/code.git refs/pull/<N>/head
git am -3 --empty=drop --directory=products/desktop/ \
--exclude='products/desktop/.github/*' \
--exclude='products/desktop/pnpm-lock.yaml' \
--exclude='products/desktop/packages/agent/pnpm-lock.yaml' \
"$PATCH"
--exclude matches after --directory is prepended, so the patterns carry the products/desktop/ prefix.
git am keeps each commit's original author and message; the commits are created and signed by you, which satisfies the signed-commit ruleset while crediting the source author.
On conflict, resolve and git am --continue; git am --abort resets.
The 3-way merge only works because step 1 fetched the source PR's objects.
.github/**: look the workflow up in MIGRATION.md's mapping table. If it is in the dropped table the change is moot. Otherwise re-apply the source change to the ported root desktop-*.yml by following the transform rules, and invoke /authoring-ci-workflows before editing.package.json change, then regenerate from products/desktop/ with pnpm install --lockfile-only, minding the minimumReleaseAge notes in MIGRATION.md.pnpm-workspace.yaml overrides) as intentional monorepo divergence: keep the monorepo side and re-apply the PR's intent on top of it.products/desktop/: pnpm install --frozen-lockfile, pnpm typecheck and pnpm --filter <pkg> test for the packages the PR touches. The desktop CI suite runs on the monorepo PR itself..github/pull_request_template.md. Carry the original description over, rewriting bare #N references as PostHog/code#N so they do not resolve to unrelated monorepo PRs. State "Ports PostHog/code#N" so the pair is linked.End a sweep with one line per source PR: ported to #X, skipped (why) or flagged for a human (why).
Never silently drop a PR from the sweep.
Take posthog/porting-code-prs 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.
The instructions reference npm.
Without those the skill loads but fails at the first command.