personio-eng-kotlin
Skills and conventions for Kotlin development at Personio.
Installation
claude plugin install personio-eng-kotlin@personio-claude-code-marketplace
What does this plugin do?
This plugin provides skills, tools, and guidance specific to Kotlin development at Personio. It covers patterns, conventions, and best practices for Kotlin backend services.
Kotlin LSP
Integrates the JetBrains Kotlin Language Server to give Claude rich language intelligence for .kt and .kts files, including go-to-definition, find references, hover info, document symbols, and more.
What you need:
- Java 17+
kotlin-lspinstalled and available on your PATH
Installing kotlin-lsp:
# macOS with Homebrew
brew install JetBrains/utils/kotlin-lsp
For manual installation, download from the kotlin-lsp releases page and add to your PATH.
Note: Currently supports JVM-only Kotlin Gradle projects.
What Claude can do with the LSP:
- Go to definition and implementation of symbols
- Find all references to a symbol
- Hover over symbols for type information
- List and search for symbols across the workspace
- Navigate call hierarchies (incoming and outgoing calls)
personio-framework skill
Makes Claude aware of Personio Framework (PF) and grounds PF-related answers in real sources instead of fabricating them.
What you need:
ghCLI, authenticated (gh auth login)git- The
personio-mcp-serverMCP connected (used for the live techdocs) - A local clone of
Personio-Internal/personio-frameworkat~/dev/personio-framework— the skill offers to clone this for you on first use
Quick Start:
# Nothing to do — the skill activates automatically when you ask a
# PF-related question, detects your service's pinned PF version from
# libs.versions.toml, and answers from the right tag of the local clone.
claude "How does PF handle multi-tenancy?"
Example:
In a Kotlin service that pins personioFrameworkBom = "20.18.0+2026-04-14" in gradle/libs.versions.toml:
You: How is gRPC resiliency set up in PF?
Claude (via personio-framework skill):
- Detects
v20.18.0+2026-04-14→ target tag.- Reads
apis/synchronous/grpc-service-development/resiliency/from the techdocs MCP for the narrative.- Reads the matching implementation at the v20.18.0+2026-04-14 tag via
git show.- Cites both a GitHub deep-link and a reproducible
git showcommand.
Why would you want this?
- No fabricated answers. Every PF claim is grounded in either the live techdocs or the pinned version's source code.
- Version-aware. Answers reflect the PF version your service actually uses, not "latest" or an LLM's memory.
- Current on conventions. Deprecations and convention changes go into techdocs first — the skill always prefers MCP for convention / deprecation questions, so you won't be told to use something that was retired since your pinned release.
- Non-invasive. The skill is read-only over
~/dev/personio-framework: nogit checkout, nogit pull, no disturbance to a clone you may also be actively editing.
Auto-loaded on Personio Kotlin service files
A PreToolUse hook in this plugin watches Read / Edit / Write calls. The first time Claude touches a Personio Kotlin service file in a session, the hook injects a one-shot system reminder pointing Claude at this skill. Subsequent matching file touches in the same session do not re-inject — Claude already has the context.
Matched files (basename, case-sensitive):
- Kotlin source and build scripts:
*.kt,*.kts(incl.build.gradle.kts,settings.gradle.kts) - Gradle config:
libs.versions.toml,gradle.properties,gradle-wrapper.properties,build.gradle(Groovy DSL) - Spring
application.*config:application.yaml,application.yml,application.properties, plus profile variantsapplication-*.yaml/application-*.yml/application-*.properties
The reminder is suppressed when the file lives in the personio-framework repo itself (detected via the repo's origin remote, so git worktrees count too): the skill bootstraps a read-only clone of that repo for consuming services, so it adds nothing when you are editing the framework's own source.
The hook never blocks a tool call; it only adds context. If you want to opt out, remove the plugin or delete hooks/hooks.json from your local install.
pf-golden-path skill
Deprecation-first advisor for Personio Framework. Surfaces @Deprecated symbols in code reviews, answers golden-path dependency questions, and reports on deprecation hot-spots — all grounded in live sources, no curated tables.
What you need:
ghCLI, authenticated (gh auth login)git- The
personio-mcp-serverMCP connected (used for golden-path / BOM curation pages) - A local clone of
Personio-Internal/personio-frameworkat~/dev/personio-framework— the skill offers to clone this on first use
Quick Start:
# The skill activates automatically on deprecation or golden-path questions.
claude "Is com.personio.framework.multitenancy.implicit.RequestContext deprecated?"
Example:
In a Kotlin service editing build.gradle.kts:
You: Can I use Rollbar for error tracking in this service?
Claude (via pf-golden-path skill):
- Reads
managing-dependencies/golden-pathfrom the techdocs MCP.- Reports Rollbar is explicitly listed as "Not on the golden path".
- Suggests the golden alternative:
io.sentry:sentry-spring-boot-starter-jakarta(BOM-managed).- Cites the techdocs entity_ref + path.
Another example — reviewing a Kotlin file:
You: Review this class for deprecated PF APIs:
import com.personio.framework.multitenancy.implicit.RequestContext ...Claude (via pf-golden-path skill):
- Detects
$TARGET_TAGfromgradle/libs.versions.toml.- Greps
@Deprecatedat that tag for eachcom.personio.framework.*import.- Lists every finding with the annotation's
messageandReplaceWithtarget.- Cites both a GitHub deep-link and a reproducible
git showcommand per finding.
Why would you want this?
- Deprecations caught before they propagate. A new file pasted for review is scanned for deprecated PF symbols at the right tag — catches warnings that would otherwise slip into the commit.
- No curated table to rot. All three sources (
@Deprecatedin the clone, golden-path techdocs, BOM-curation techdocs) are live and authoritative. Zero maintenance. - Dependency decisions grounded. "Can I use Micronaut / Rollbar / Quarkus?" gets a tagged answer from the golden-path reference, not an LLM guess.
- Version-aware. Same substrate as
personio-framework: answers reflect your service's pinned PF version. - Non-invasive. Read-only over
~/dev/personio-framework.
pf-upgrades
Read-only advisor for Personio Framework version upgrades. Walks the
CHANGELOG slice between the pinned start tag (from libs.versions.toml)
and the requested target (default: server-side latest), surfaces any
hand-written upgrade guides first, and flags release-date deltas that
cross the 60-day deprecation-notice window.
What you need:
~/dev/personio-frameworklocally cloneable (the skill bootstraps it viagh repo clone Personio-Internal/personio-frameworkif missing).ghauthenticated (gh auth login).- A service with
gradle/libs.versions.tomlpinningpersonioFrameworkBom(or a user-supplied start version if you're asking from outside a service).
Quick Start:
# Ask the skill in Claude Code, e.g.:
"Help me upgrade from PF 20.11 to 20.18."
"What's new in PF 20.18?"
"What CVEs were patched between 20.14 and 20.18?"
Example — named range:
You: Help me upgrade from PF v20.11.0+2026-02-24 to v20.18.0+2026-04-14.
Skill: Upgrade PF v20.11.0+2026-02-24 → v20.18.0+2026-04-14 (49 days, within 60-day window).
📘 Read first — upgrade guides
- 20.11.0 → 20.12.0:
@EnableMultitenancyProtectionnow bundlesContextPropagationConfiguration… [link]- 20.12.0 → 20.13.0: automatic context propagation for
RequestContextfields across thread boundaries … [link]⚠️ Breaking changes (grouped by
libs/…/plugins/…)✨ New features (grouped)
🔒 Security —
Spring Boot 3.5.10 → 3.5.12 (CVE-2026-24281);Datadog agent 1.60.x → 1.60.4;N other routine Dependabot bumps.
Example — >60-day jump:
You: Upgrade my service from PF v20.0.0+2025-12-15 to v20.18.0+2026-04-14.
Skill: Delta: 120 days — exceeds the 60-day notice window. Deprecations introduced near the start tag may already be hard compile errors at the target. Recommend stepping through an intermediate hop at v20.11.0+2026-02-24 first (≈ start + 60 days). Full range report follows below anyway.
Why would you want this?
- One command for the whole upgrade range — no more skimming eight CHANGELOG entries manually.
- Every claim is reproducible — deep-links and
git showcommands under each bullet. - 60-day policy is baked in — you don't have to remember to check whether your jump is safe.
- CVE signal is never lost — routine Dependabot bumps collapse, but CVE entries stay verbatim at the top of the Security section.
- Advisory-only — the skill never edits
libs.versions.tomlor runsgradle. You keep control of the actual bump.
ppm
Read-only advisor for Personio Plugin Manager (PPM) — Personio's Gradle plugin-convention system. Answers "what does this convention do?", "is it on by default?", "how do I turn it off?", "what PPM plugins should I enable?", and enumeration requests by reading the PPM README (plus per-convention deep-dive pages where they exist) at the pinned PF version.
What you need:
~/dev/personio-frameworklocally cloneable (the skill bootstraps it viagh repo clone Personio-Internal/personio-frameworkif missing).ghauthenticated (gh auth login).- A service with
gradle/libs.versions.tomlpinningpersonioFrameworkBom(or falls back to the latest tag).
Quick Start:
# Ask the skill in Claude Code, e.g.:
"What does PactConvention do?"
"How do I disable the JacocoPluginConvention?"
"List all PPM conventions."
Example — toggle question:
You: How do I disable the JacocoPluginConvention?
Skill:
JacocoPluginConventionis on by default when the Jacoco plugin is applied. To disable:# in gradle.properties personio.convention.jacoco=falseSource:
plugins/personio-plugin-manager/README.mdatv20.18.0+2026-04-14— github /git -C ~/dev/personio-framework show v20.18.0%2B2026-04-14:plugins/personio-plugin-manager/README.md
Example — deep-dive lookup:
You: Explain the DataRegistryConvention.
Skill: Reads both the README row and
DataRegistryConvention.mdat the pinned tag, summarizes the local-development workflow, names the keywordpersonio.convention.data.registry, and cites both files.
Why would you want this?
- One lookup, one answer — no tab-switching between README, per-convention pages, and source.
- Toggle snippets are ready to paste — the skill emits the exact
gradle.propertiesline for the convention you asked about. - Version-pinned — all answers are grounded in the PF tag your service actually uses, not the latest main.
- Advisory-only — the skill never edits
gradle.propertiesorbuild.gradle.kts. You keep control of the actual change.
debug-with-mirrord
Run a Personio microservice locally wrapped in
mirrord so traffic matching your session header is
stolen from the dev cluster to your laptop, then drive end-to-end test
scenarios via API calls or browser automation. Replaces the IntelliJ
[mirrord] <service> run configuration for agentic workflows.
What you need:
mirrordCLI (brew install metalbear-co/mirrord/mirrord)- Active AWS SSO session for EKS auth (
aws sso login --profile dev) kubectlcontext set todev(or whichever cluster the service's.mirrord/mirrord.jsontargets)- A service repo containing
.mirrord/mirrord.json - Recommended:
personio-eng-commonplugin installed for thedev-authskill — used to mint dev JWTs for API/gRPC calls during scenarios. Without it, Claude will ask you how to obtain a token.
Quick Start:
# In your service repo:
claude "Start payroll-data-import-service with mirrord and upload a YTD file."
The skill inspects .mirrord/mirrord.json, launches the service via the
bundled mirrord-start.sh, polls /health-check/readiness, then runs the
requested scenario — handing off to the dev-auth skill (in
personio-eng-common) for token minting and hitting localhost:<port>
directly so downstream I/O still routes through the remote pod.
Example — API scenario:
You: Start payroll-data-import-service with mirrord and import the employees from
playground/employees.csvfor company 12345.Claude (via debug-with-mirrord skill):
- Reads
.mirrord/mirrord.json; reports target rollout, namespace, and resolved session header (baggage: mirrord-session=$USER).- Checks for stale mirrord PIDs in
/tmp/mirrord-*.pidto avoid session-header collisions.- Launches via
mirrord-start.sh --service-dir .and waits for/health-check/readinessto return 200.- Hands off to the
dev-authskill to mint a user-scoped dev token.- POSTs the import request against
http://localhost:8080/...and tails/tmp/mirrord-<service>.logto confirm the local controller handled it.- Stops the session with
mirrord-stop.sh --service-dir .when done.
Example — concurrent sessions:
You: Start a second mirrord session for
notification-servicewhilepayroll-data-import-serviceis still running.Claude: Detects an existing PID file. Without an override both sessions would match the same
mirrord-session=$USERheader and traffic routing becomes non-deterministic. Offers to (a) stop the existing session, or (b) start the new one with--session-id $USER-notification-serviceand prints the matchingbaggageheader to copy into curl / the Personio Developer Extension.
Why would you want this?
- No IntelliJ required — agentic workflows can start, exercise, and stop a service end-to-end from the terminal.
- Real downstream behaviour — DB, Temporal, gRPC clients, S3, env vars all still route through the remote pod under mirrord, so business logic executes identically to a dev-URL call.
- Safe concurrency — collision detection and an explicit
--session-idoverride stop two sessions from silently fighting over the samemirrord-sessionheader. - Localhost-by-default — the skill calls
http://localhost:<port>directly, so you don't need to know the public dev URL or wrangle baggage headers for routine testing. - Graceful cleanup via
mirrord-stop.sh