This skill should be used when implementing or modifying OpenRewrite recipes in the Liftwizard project, when the user asks to "create a recipe", "implement a Refaster template", "convert to Refaster", "add an OpenRewrite transformation", or discusses recipe implementation patterns. Provides guidance on Refaster templates, traditional recipe implementation, type safety, and common patterns.
Guidance for implementing and modifying OpenRewrite recipes in the Liftwizard project, based on lessons learned from production experience.
Use this skill when:
For test-related guidance, see the separate openrewrite-test skill.
✅ Good Use Cases:
❌ Poor Use Cases:
@Repeated annotation support)Rule: Combine multiple @BeforeTemplate methods into one nested class when they produce the same @AfterTemplate output.
Within a single nested class, you can have multiple @BeforeTemplate methods that all share one identical @AfterTemplate. This is useful when semantically different source patterns should transform to the same target pattern:
size() == 0 vs 0 == size() → isEmpty()size() < 1 vs size() <= 0 → isEmpty()left == null ? right == null : left.equals(right) vs left == right || (left != null && left.equals(right)) → Objects.equals(left, right)When to create separate nested classes:
Create separate nested classes when the @AfterTemplate output differs in any way:
assertThat(x).isNotEmpty() vs assertThat(x).as(message).isNotEmpty() → separate classesfoo(x) vs bar(x) → separate classesWhen creating Refaster templates:
RecipeName (e.g., ECSimplifyNegatedSatisfies)RecipeNameRecipes (e.g., ECSimplifyNegatedSatisfiesRecipes)Recipes classPrefer classpath() when possible:
.classpath("eclipse-collections-api") to JavaTemplate builders for real Eclipse Collections types.classpath("eclipse-collections") for implementation classes if neededUse dependsOn() when necessary:
Verify class stubs in AssertJ migration tests (eclipse-collections-testutils classpath doesn't work)Experiment incrementally:
dependsOn() text blockclasspath() entry to fixProcess:
.typeValidationOptions(TypeValidation.none()) lineCommon Fix: Add appropriate classpath() entries to JavaTemplate builders to provide real type information
Fundamental Limitations (cannot remove TypeValidation.none()):
.typeValidationOptions(TypeValidation.none())Add support for both explicit negation (!method()) and Predicates.not() wrapping:
!iterable.noneSatisfy(p) → iterable.anySatisfy(p)Iterate.noneSatisfy(iterable, Predicates.not(p)) → Iterate.anySatisfy(iterable, p)Predicates imports are correctly removedFor sorted collection transformations, add overloads that accept a Comparator:
TreeSortedSet.newSet(Comparator, Arrays.asList(...)) → SortedSets.mutable.with(Comparator, ...)Comparator.naturalOrder() and Comparator.reverseOrder()Until OpenRewrite issue #4397 is resolved:
JavaIsoVisitor with dynamic placeholder building@Repeated annotation is supportedWhen refactoring from traditional Recipe to Refaster, document in class javadoc:
@Repeated annotation for varargs support in RefasterSearch for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer