grpc-migrate

Automates gRPC service migrations across Personio's service estate.

Installation

claude plugin install grpc-migrate@personio-claude-code-marketplace

Once installed, invoke from any repository:

/grpc-migrate

The skill immediately asks which mode to run.

What does this plugin do?

Provides a full migration playbook for replacing deprecated gRPC service calls with their new versions — behind a feature flag, with tests for both flag states, and a draft PR as output.

What you need: gh CLI authenticated, ./gradlew available in the target repo, and a data-registry version that contains the target RPC.

Three modes:

ModeWhen to use
migrateApply the full playbook to one repository — discovers call sites, plans and applies the migration, runs lint + tests + clean build + smoke test, opens a draft PR
update trackerRefresh an existing tracker after a batch of PRs land — checks merged PRs, newly self-migrated repos, and resolves placeholder feature flag names from open PR diffs
discoverSearch Personio-Internal org-wide for all consumers of a deprecated service and write a migration tracker .md file

Why would you want this?

  • Deprecating a proto service used by 10+ repositories? Run discover once to produce a tracker, then migrate each repo in turn — the playbook handles the full cycle end to end.
  • Each migration is feature-flagged with tests for both the flag-off and flag-on paths. The skill audits each call site for error handling, retry logic, logging, and response mapping to make sure nothing is silently dropped.
  • update tracker keeps your migration status doc current without re-running the full playbook.

Mode: migrate

With a tracker (most common)

Once you have a tracker from a discover run, point the skill to it and pick the next pending repo by number:

/grpc-migrate
  → migrate
  → company/COMPANY-GRPC-MIGRATION-TRACKER.md
  → 3                                           # pick repo #3 from the pending list
  → ~/dev                                       # where your local clones live
  → 1.0.20260313093041                          # data-registry version with the target RPC
  → ORG-3671                                    # JIRA ticket
  → no                                          # no known breaking changes
  → WAC-5012-company-grpc-v2-migration          # feature flag name

The skill reads the deprecated service(s) and target service from the tracker header — no need to type them. It then:

  1. Pulls the latest default branch of the target repo
  2. Discovers all call sites for the deprecated service(s) and identifies which methods are called
  3. Audits each call site for error handling, retry logic, logging, and response mapping to carry forward
  4. Reads the target API, determines field mask requirements, and presents a migration plan for approval
  5. Applies the changes behind the feature flag (tests both flag-off and flag-on paths)
  6. Runs compileKotlintestktlintCheckclean build → smoke test
  7. Opens a draft PR with a full description: changed call sites, field mask rationale, reviewer checklist
  8. Updates the tracker row to 👀 In review

Without a tracker

If no tracker exists yet, provide the deprecated and target services manually:

/grpc-migrate
  → migrate
  → no                                                               # no tracker
  → workflow-platform                                                # repo name
  → ~/dev
  → 1.0.20260313093041
  → personio.proto.entity.core.company.api.v1.CompanyService        # deprecated (can be multiple)
  → personio.proto.entity.core.company.api.v1alpha1.CompanyService  # second deprecated service
  → personio.proto.core_hr.company.api.v1.CompanyService            # target service
  → ORG-3671
  → no
  → WAC-5012-company-grpc-v2-migration

The skill discovers which specific methods are called at each site and infers READ vs. WRITE from method names — no need to specify these.

Placeholder feature flag names

If the owning team hasn't created the cleanup ticket yet, use any placeholder:

  → PLACE-HOLD-TBD

The flag name is defined as a single const val, so renaming later is a one-line change. The PR checklist will include a reminder to create the cleanup ticket before merging.


Mode: update tracker

Refreshes a tracker without running full migrations. Run this periodically to keep the tracker current after a batch of PRs land.

/grpc-migrate
  → update tracker
  → company/COMPANY-GRPC-MIGRATION-TRACKER.md

The skill:

  • Checks each 👀 In review PR — marks merged ones as ✅ Migrated (behind flag, cleanup pending)
  • Checks each ⏳ Pending repo via gh search code — if the target stub is found alongside the deprecated stub, investigates open/merged PRs and updates the status
  • For any row with a placeholder feature flag, reads the open PR's diff and description to find the real const val name and updates the tracker automatically
  • Rewrites the tracker and prints a summary

Sample summary

Tracker updated:
- 2 PRs marked as merged: workflow-platform, surveys-service
- 1 pending repo found to have an open PR (→ 👀 In review): attendance-service
- 1 feature flag placeholder resolved from PR diff: workflow-platform (WAC-5012-company-grpc-v2-migration)
- 11 repos still pending
- 2 rows unchanged
- ⚠️ Placeholder feature flag names not yet resolved: compensation-service (PLACE-HOLD-TBD)

Mode: discover

Searches the Personio-Internal org for all services still calling a deprecated gRPC service and writes a migration tracker.

Creating a new tracker

/grpc-migrate
  → discover
  → no                                                               # no existing tracker
  → personio.proto.entity.core.company.api.v1.CompanyService        # deprecated (can be multiple)
  → personio.proto.entity.core.company.api.v1alpha1.CompanyService
  → company/COMPANY-GRPC-MIGRATION-TRACKER.md                       # where to save

The skill runs gh search code for CompanyServiceGrpc and CompanyServiceGrpcKt across the org, cross-checks which repos also have the target stub already (already-migrated or in-progress), and writes a fully-populated tracker:

| Repository | Deprecated RPC(s) | Target RPC | Jira | Migration PR | PR Status | Feature Flag | Flag Status |
|---|---|---|---|---|---|---|---|
| [workflow-platform](…) | `v1.CompanyService` | `core_hr.v1.CompanyService` | — | — | ⏳ Pending | — | — |
| [surveys-service](…)   | `v1.CompanyService` | `core_hr.v1.CompanyService` | — | [#268](…) | 👀 In review | — | 0% rollout |

Updating an existing tracker with newly-found consumers

Point discover at an existing tracker — it skips repos already listed and appends only new ones:

/grpc-migrate
  → discover
  → company/COMPANY-GRPC-MIGRATION-TRACKER.md   # existing tracker
  → personio.proto.entity.core.company.api.v1.CompanyService

Tips

  • Always let the skill open PRs as drafts. Do not mark ready until the owning team has reviewed and tested.
  • The skill will not touch gRPC service implementations (@GrpcService classes). Only call sites are migrated — server-side handlers are permanently excluded.
  • New stubs always reuse the same @GrpcClient channel as the deprecated stub they replace. Introducing a separate channel to the same host is wrong even if another channel happens to resolve there.
  • Run update tracker after a batch of migrations rather than re-running discover — it's faster and won't duplicate rows.
  • Extracted shared logic: if both the flag-off and flag-on paths share response mapping or auth setup, the skill extracts it into a private helper rather than duplicating it in both branches.