From reforge
Orchestrate large-scale Java/Kotlin refactorings using IntelliJ's refactoring engine. Operations execute in strict serial order, so each step sees the results of previous ones. Analyzes codebase structure, generates refactoring config, and executes via headless IntelliJ plugin.
How this skill is triggered — by the user, by Claude, or both
Slash command
/reforge:reforgeThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are orchestrating a large-scale architectural refactoring using the **Reforge** IntelliJ plugin. Reforge executes refactoring operations headlessly via CLI + YAML config, using IntelliJ's refactoring engine for full reference/import updating.
You are orchestrating a large-scale architectural refactoring using the Reforge IntelliJ plugin. Reforge executes refactoring operations headlessly via CLI + YAML config, using IntelliJ's refactoring engine for full reference/import updating.
Prerequisites: IntelliJ IDEA must be installed. The Reforge IntelliJ plugin must be installed (see below).
The wrapper script at ~/.claude/plugins/marketplaces/notiriel-reforge/scripts/reforge.sh launches IntelliJ headlessly without opening a window or conflicting with a running IDE.
Check if the Reforge plugin is installed in IntelliJ:
find ~/Library/Application\ Support/JetBrains/IntelliJIdea*/plugins \
~/.config/JetBrains/IntelliJIdea*/plugins \
~/.local/share/JetBrains/IntelliJIdea*/plugins \
-maxdepth 1 -name "reforge" -type d 2>/dev/null
If not found, install it:
idea installPlugins ch.riesennet.reforge https://raw.githubusercontent.com/notiriel/reforge/main/updatePlugins.xml
Before doing anything else, confirm the project is in a compilable state. Reforge relies on IntelliJ's indexer and refactoring engine, which produce incorrect results on broken code (stale imports, unresolved references, package/path mismatches).
# Maven
cd <project-path> && mvn compile -q
# Gradle
cd <project-path> && ./gradlew classes -q
If the build fails, stop and tell the user. The project must compile cleanly before Reforge can run. Do NOT generate a refactoring config for a project that doesn't build.
Before generating config, understand the codebase:
find <project>/src -type d | head -50**/*.java or **/*.kt filessrc/test/java layout — identify which test classes correspond to which production classesBased on the user's goal, determine which operations to use:
| Goal | Operations |
|---|---|
| Package reorganization | move operations |
| Hexagonal architecture | move + extract-interface + replace-dependency |
| Domain-driven structure | move to domain packages |
| Dependency inversion | extract-interface + replace-dependency |
reforge.yamlWrite a YAML config file in the target project root:
operations:
# Move operations — group related classes together
- type: move
target: com.example.app.task.model
sources:
- com.example.app.model.Task* # Wildcards match multiple classes
- type: move
target: com.example.app.task.service
sources:
- com.example.app.service.TaskService*
# Extract interface — create ports/interfaces from implementations
- type: extract-interface
class: com.example.app.task.service.TaskService
interface: com.example.app.task.port.TaskPort
methods: [findAll, findById, createTask]
# Replace dependency — swap concrete types with interfaces
- type: replace-dependency
in: com.example.app.task.controller.TaskController
replace: com.example.app.task.service.TaskService
with: com.example.app.task.port.TaskPort
Operations execute in strict serial order — each operation completes fully before the next one begins. This means later operations see the results of earlier ones (moved classes, new interfaces, updated references). Use this to your advantage:
Always include test classes: When moving a production class, include its corresponding test class in the same move operation. Reforge places test classes into the test source root automatically, so they can share the same target package. For example, if moving TaskService to com.example.app.task.service, also include TaskServiceTest as a source — it will end up in src/test/java/com/example/app/task/service/.
- type: move
target: com.example.app.task.service
sources:
- com.example.app.service.TaskService
- com.example.app.service.TaskServiceTest # test class moves to test source root
If you are using wildcards, the pattern will already match test classes (e.g., TaskService* matches both TaskService and TaskServiceTest). Verify this by checking src/test/java for any test classes that correspond to the production classes being moved — if a test class wouldn't be matched by an existing wildcard, add it explicitly.
Wildcard patterns:
* matches within a single segment (e.g., Task* matches Task, TaskStatus, TaskService)** matches zero or more package segments (e.g., com.example.**.*Entity)# Dry run first to preview
~/.claude/plugins/marketplaces/notiriel-reforge/scripts/reforge.sh <project-path> <project-path>/reforge.yaml --dry-run
# Real run
~/.claude/plugins/marketplaces/notiriel-reforge/scripts/reforge.sh <project-path> <project-path>/reforge.yaml
After execution, run the project's test suite:
cd <project-path>
# For Maven projects
mvn clean verify
# For Gradle projects
./gradlew test
Tell the user:
Because operations run in order, you can move a single class first, then use a wildcard to move the remaining classes to a different package. The wildcard in the second step won't match the already-moved class.
operations:
# Step 1: Move GlobalExceptionHandler to common — runs first
- type: move
target: com.example.app.common.exception
sources:
- com.example.app.exception.GlobalExceptionHandler
# Step 2: Move remaining exception classes to task — sees GlobalExceptionHandler already gone
- type: move
target: com.example.app.task.exception
sources:
- com.example.app.exception.*
operations:
- type: move
target: com.example.app.order.model
sources:
- com.example.app.model.Order*
- type: move
target: com.example.app.order.repository
sources:
- com.example.app.repository.Order*
- type: move
target: com.example.app.order.service
sources:
- com.example.app.service.OrderService*
operations:
# First move to domain structure
- type: move
target: com.example.app.order.domain
sources:
- com.example.app.model.Order*
- type: move
target: com.example.app.order.application
sources:
- com.example.app.service.OrderService*
# Then extract ports
- type: extract-interface
class: com.example.app.order.application.OrderService
interface: com.example.app.order.port.in.OrderUseCase
methods: [createOrder, findOrder, listOrders]
# Wire controllers to ports
- type: replace-dependency
in: com.example.app.order.adapter.in.OrderController
replace: com.example.app.order.application.OrderService
with: com.example.app.order.port.in.OrderUseCase
reforge.sh: No such file: Ensure the Claude Code plugin is installed (/plugin install reforge@notiriel-reforge)npx claudepluginhub notiriel/reforge --plugin reforgeDetects Java version from pom.xml or build.gradle and suggests refactorings like lambdas (8+), streams (8+), records (16+), pattern matching (17+), plus universal changes like method extraction and dead code removal.
Performs safe refactoring: extract functions/components/hooks/modules/classes, rename/move/restructure symbols/files, inline code, detect dead code/smells using test-driven methods.
Discovers architectural friction — shallow modules, god files, duplication, coupling — and proposes structural refactors with competing interface options and a project-local RFC.