with one click
openlore-plan-refactor
// Identify the highest-priority refactoring target using static analysis, assess its blast radius, and produce a detailed written plan saved to .openlore/refactor-plan.md. Makes no code changes.
// Identify the highest-priority refactoring target using static analysis, assess its blast radius, and produce a detailed written plan saved to .openlore/refactor-plan.md. Makes no code changes.
Persistent architectural memory for this codebase. Call `orient(task)` before reading source files to get the relevant functions, callers, spec sections, and insertion points for any task ā saving 15,000ā50,000 tokens of file-by-file rediscovery.
Run a full static analysis of a project using openlore and summarise the results ā architecture, call graph, top refactoring issues, and duplicate code. No LLM required.
Transform a feature idea into an annotated story. Detects greenfield vs brownfield automatically ā uses Domain Sketch for greenfield (no existing code), Constrained Option Tree for brownfield (existing codebase with openlore analysis).
Debug a problem by anchoring root-cause analysis in openlore structural knowledge. Uses orient + search_specs + analyze_impact to form an explicit hypothesis before reading code. Enforces RED/GREEN test verification.
Apply the refactoring plan produced by openlore-plan-refactor. Reads .openlore/refactor-plan.md and re-reads it before each change to stay on track. Requires a confirmed plan to exist before running.
Reverse-engineer OpenSpec specifications from an existing codebase. Performs "code archaeology" ā extracting what code actually does and documenting it as structured OpenSpec specs across all detected domains.
| name | openlore-plan-refactor |
| description | Identify the highest-priority refactoring target using static analysis, assess its blast radius, and produce a detailed written plan saved to .openlore/refactor-plan.md. Makes no code changes. |
| license | MIT |
| compatibility | openlore MCP server |
| user-invocable | true |
| allowed-tools | ["ask_followup_question","use_mcp_tool","read_file","write_file","openlore-analyze-codebase"] |
Trigger this skill whenever the user asks to plan a refactoring on a codebase, with phrasings like:
/openlore-plan-refactorThis skill modifies no code files. It only produces .openlore/refactor-plan.md.
To apply the plan, use the openlore-execute-refactor skill.
The plan must be written so that every entry in the change sequence is independently executable and testable.
Each change = one atomic edit ā one diff verification ā one full test run ā ā or rollback.
This is not a final gate at the end. Testing is a mandatory sub-step after every single change. The plan must make this cycle explicit and impossible to skip.
For Devstral Small 2: each change must touch at most 50 contiguous lines in the source file. If a logical extraction exceeds this limit, split it into smaller sub-changes, each with its own test gate.
If the user has already named a specific file or function to refactor:
Ask the user which project to analyze, or confirm the current workspace root.
Analyze the project via the openlore MCP server. If a recent analysis already exists, skip unless the user explicitly requests a fresh run.
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>analyze_codebase</tool_name>
<arguments>{"directory": "$DIRECTORY"}</arguments>
</use_mcp_tool>
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>get_refactor_report</tool_name>
<arguments>{"directory": "$DIRECTORY"}</arguments>
</use_mcp_tool>
Present the top 5 candidates:
| Function | File | Issues | Priority score |
|---|
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>get_duplicate_report</tool_name>
<arguments>{"directory": "$DIRECTORY"}</arguments>
</use_mcp_tool>
If a top candidate appears in a clone group, prepend a deduplication note to the plan:
"ā ļø
<function>has N near-clones. Consolidate them first to reduce the blast radius of this refactor."
Before presenting a choice to the user, check test coverage for the files containing the candidates. Detect the coverage tool from the project:
| Ecosystem | Command |
|---|---|
| Node.js | npm test -- --coverage --collectCoverageFrom="<files>" |
| Python | pytest --cov=<module> --cov-report=term-missing |
| Rust | cargo tarpaulin --include-files <files> |
| Go | go test -cover ./... |
Enrich the candidate table:
| Function | File | Priority | Coverage |
|---|---|---|---|
| ... | ... | ... | 72% ā / 35% ā ļø / 0% š« |
Thresholds:
| Coverage | Badge | Meaning |
|---|---|---|
| ā„ 70% lines | ā | Safe to refactor |
| 40ā69% lines | ā ļø | Write characterisation tests first |
| < 40% lines | š | Strongly discouraged |
| 0% (no tests) | š« | Blocked ā propose a test harness first |
If all candidates are below 40%:
"Every high-priority target has insufficient test coverage (< 40%). I recommend writing a minimal test harness for at least one target before proceeding. Would you like me to suggest test cases based on the function signatures?"
Get the condensed view (callers, callees, body, test coverage) in one call:
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>get_minimal_context</tool_name>
<arguments>{"directory": "$DIRECTORY", "functionName": "$FUNCTION_NAME"}</arguments>
</use_mcp_tool>
What to read before deciding whether to proceed:
function.riskLevel ā "high" = up to 24 callers/callees shown; read all, they are all in scope.callers[*].callType ā all "awaited" = async interface frozen; extracting or splitting requires updating every call site.testedBy[*].confidence ā "imported" only = vi.mock() can neutralize; write a characterisation test before refactoring.Then get full impact analysis:
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>analyze_impact</tool_name>
<arguments>{"directory": "$DIRECTORY", "symbol": "$FUNCTION_NAME"}</arguments>
</use_mcp_tool>
Note: risk score (0ā100), recommended strategy (extract / split / facade / delegate), top 5 upstream callers and downstream callees.
If riskLevel is "high" or impact risk score ā„ 60, check cluster scope:
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>get_cluster</tool_name>
<arguments>{"directory": "$DIRECTORY", "functionName": "$FUNCTION_NAME"}</arguments>
</use_mcp_tool>
clusterDensity < 0.05 ā extract target independentlyclusterDensity 0.05ā0.15 ā include internalCallGraph callers in risk sectionclusterDensity > 0.15 ā refactor whole cluster together or not at all<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>get_subgraph</tool_name>
<arguments>{"directory": "$DIRECTORY", "functionName": "$FUNCTION_NAME", "direction": "both", "format": "mermaid"}</arguments>
</use_mcp_tool>
Show the Mermaid diagram to the user.
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>get_low_risk_refactor_candidates</tool_name>
<arguments>{"directory": "$DIRECTORY", "filePattern": "$TARGET_FILE", "limit": 5}</arguments>
</use_mcp_tool>
Cross-reference with the subgraph from Step 5: a good first extraction candidate already appears as a callee of the target function.
Before designing the change sequence, identify where extracted functions should land. This avoids creating helpers in the wrong file or layer.
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>suggest_insertion_points</tool_name>
<arguments>{"directory": "$DIRECTORY", "query": "extract helper from $FUNCTION_NAME", "limit": 5}</arguments>
</use_mcp_tool>
For each candidate, note its role and strategy. Prefer candidates that already call into ā or are called by ā the target function (visible in the Step 5 subgraph).
Design an ordered sequence of atomic changes based on the strategy from Step 4.
Each change must touch at most 50 contiguous lines in the source file. If a logical extraction requires moving more than 50 lines in one pass, split it into sub-changes:
file:lineREAD plan entry ā EDIT (targeted, ⤠50 lines) ā DIFF verify ā TEST
āā green ā mark ā
, next change
āā red ā git checkout HEAD -- <file>, diagnose, retry
after 3 failed retries ā STOP, report to user
The plan must show this cycle in the change sequence, not just in a footnote.
Rules per strategy:
| Strategy | Rule |
|---|---|
split | Decompose into N sub-functions in the same file unless they clearly belong elsewhere |
extract | Place in the nearest cohesive module or create a new file if none exists |
facade | Keep the original signature, delegate to smaller functions; companion module if > 300 lines |
delegate | Move ownership logic to callers; update every caller file in the upstream chain |
Present the full sequence and wait for confirmation before writing the plan file.
.openlore/refactor-plan.mdFill every section ā leave nothing as "TBD".
# Refactor Plan
Generated: <ISO date>
Workflow: /openlore-plan-refactor ā /openlore-execute-refactor
## Target
- **Function**: <n>
- **File**: <relative path>
- **Lines**: <start>ā<end>
- **Risk score**: <0ā100>
- **Strategy**: <extract | split | facade | delegate>
- **Priority score before refactor**: <value>
## Why
- <issue 1>
- <issue 2>
## Callers (upstream ā must not break)
| Caller | File |
|---|---|
## Callees (downstream ā candidates for extraction)
| Callee | File |
|---|---|
## Coverage baseline
- **File**: <target file>
- **Coverage**: <X>% lines, <Y>% branches
- **Status**: ā
safe / ā ļø caution / š discouraged
- **Test command**: <exact command>
## Change sequence
Each change is a complete mini-development: edit ā diff ā test ā ā
or rollback.
Never advance to the next change without a green test gate.
### Change 1 ā <short label>
- **What**: extract lines <start>ā<end> (logic: <one-line description>)
- **Lines touched in source**: ~<N> lines (must be ⤠50)
- **New function name**: `<n>`
- **Target file**: `<path>` (<new file | existing file ā reason>)
- **Target class**: `<ClassName>` or none
- **Call sites to update**: <list each file:line>
- **Expected diff**: +<N> lines in <target file>, -<M> lines in <source file>
- **Test gate**: `<exact test command>`
- **Retry limit**: 3 attempts ā if still red after 3, stop and report
### Change 2 ā <short label>
...
## Acceptance criteria
- Priority score drops below <target score> in `get_refactor_report`
- Function exits the top-5 list
- Full test suite passes (green)
- `git diff --stat` shows only the expected files
## Restore point
Hash: <to be filled by the execute workflow>
Once the file is written, record the refactoring decision so it appears in the decisions workflow at commit time:
<use_mcp_tool>
<server_name>openlore</server_name>
<tool_name>record_decision</tool_name>
<arguments>{
"directory": "$DIRECTORY",
"title": "Refactor $TARGET_FUNCTION into smaller units ($STRATEGY)",
"rationale": "$PRIMARY_REASON from the Why section above",
"consequences": "Callers unchanged; complexity distributed across $N extracted helpers",
"affectedFiles": ["$TARGET_FILE"]
}</arguments>
</use_mcp_tool>
Then:
"Plan written to
.openlore/refactor-plan.md. Review it, then run/openlore-execute-refactorto apply the changes."