| name | cocosearch-refactoring |
| description | Use when planning a refactoring, extracting code into a new module, renaming across the codebase, or splitting a large file. Guides impact analysis and safe step-by-step execution using CocoSearch. |
CocoRefactoring Skill
A systematic workflow for safe code refactoring. This skill guides you through complete impact analysis using semantic search, then executes changes step-by-step with your confirmation at each gate.
Philosophy: Refactoring on incomplete information is risky. This workflow ensures you see the full picture before touching any code.
Pre-flight Check
- Resolve index name (use the resolved name for all operations):
- Try
cocosearch.yaml for indexName field -- if found, use it
- If no config file, call
list_indexes() and match the current project's directory name against available indexes. The MCP tools auto-derive index names from directory paths (e.g., my-project/ -> my_project), so a match is likely if the repo was indexed without a config file.
- If no match found, the project is genuinely not indexed -- indexing is REQUIRED. Refactoring needs 100% accurate dependency data. Do NOT abandon CocoSearch tools just because
cocosearch.yaml is missing.
list_indexes() to confirm project is indexed
index_stats(index_name="<resolved-name>") to check freshness
- Stale (>7 days) → strongly recommend reindexing. Stale data can miss critical dependencies.
-
Check dependency freshness — call get_file_dependencies on the target file (or any known file):
get_file_dependencies(file="<target-file>", depth=1)
- If response contains
warnings with type deps_outdated or deps_branch_drift:
Strongly recommend re-extracting. Refactoring on stale dependency data risks missing affected files.
"Dependency data is outdated. I strongly recommend re-extracting before proceeding. Want me to run dependency extraction? (index_codebase with extract_deps=True)"
- If response contains
warnings with type deps_not_extracted:
"No dependency data found. I'll fall back to search-based impact analysis, but dependency data provides more reliable coverage. Want me to extract dependencies first?"
- If no warnings: Proceed with dependency-based impact analysis.
-
Linked index health (if cocosearch.yaml has linkedIndexes):
- Check the
warnings array from index_stats() for entries starting with "Linked index"
- If stale/missing: warn user — "Linked index 'X' is stale/missing. Cross-project impact analysis may miss affected files. Want me to reindex?"
Step 1: Understand the Refactoring Goal
Parse the user's description to identify the refactoring type and target.
Common refactoring types:
- Extract: Move code into new module/service/class
- Rename: Change symbol name across codebase (function, class, variable)
- Split: Break large file into smaller focused files
- Move: Relocate code between existing modules
- Signature change: Modify function/method interface or API contract
Identify the target:
- Which file(s) contain the code being refactored?
- Which symbol(s) are the primary focus? (function name, class name, module name)
- What is the current scope? (single file, module, cross-cutting concern)
Confirm with user: "I understand you want to [refactoring type] [target symbol/file]. Is this correct?"
Step 2: Impact Analysis (Full Dependency Map)
This is the most critical step. Build a complete picture of what will be affected by the change.
2a. Dependency Graph Analysis (Fast Path)
Start here. If the project has a dependency index (cocosearch index . --deps), use the dependency MCP tools for instant, complete impact analysis:
Forward dependencies (what does the target depend on):
get_file_dependencies(file="<target_file>", depth=2)
Reverse impact (what depends on the target):
get_file_impact(file="<target_file>", depth=3)
These tools return transitive dependency/impact trees — far more complete than search-based heuristics. The impact tree shows the full blast radius of changing a file.
If dependency tools return results: You already have the complete impact map. Skip to 2b (test coverage) and use the dependency data as your primary source. The search-based approaches below become supplementary.
If dependency tools are unavailable (no deps index, or the file isn't tracked): Fall back to the search-based approaches below.
2a-fallback. Find All Usages (Search-Based)
Direct symbol references:
search_code(
query="<target_symbol>",
symbol_name="<target_symbol>*",
use_hybrid_search=True,
smart_context=True
)
Cross-project search: If linkedIndexes is configured in cocosearch.yaml, searches automatically expand to linked indexes. For ad-hoc multi-project refactoring, pass index_names=["project1", "project2"] to find usages across codebases.
Query rewrite: If the optional query-rewrite controller is enabled, pass rewrite_query=False when searching precise terms (exact identifiers, symbol_name/symbol_type filters) so they are matched verbatim. No effect when the controller is disabled.
Use glob patterns in symbol_name to catch variants. For example:
- Target: "User" →
symbol_name="User*" finds User, UserProfile, UserService, UserRepository
- Target: "authenticate" →
symbol_name="authenticate*" finds authenticate, authenticate_user, authenticate_request
Import references (Python):
search_code(query="import <target_module>", use_hybrid_search=True)
search_code(query="from <target_module> import", use_hybrid_search=True)
Import references (JavaScript/TypeScript):
search_code(query="import { <target_symbol> }", use_hybrid_search=True)
search_code(query="from '<target_module>'", use_hybrid_search=True)
Include references (C/C++):
search_code(query="#include \"<target_file>\"", use_hybrid_search=True)
2b. Find Test Coverage
Test files referencing target:
search_code(
query="test <target_symbol>",
symbol_name="test_*<target>*",
symbol_type="function",
use_hybrid_search=True
)
Filter results to test directories: Look for paths containing test_/, tests/, __tests__/, spec/.
Coverage assessment:
- High coverage: Multiple test files, integration + unit tests
- Medium coverage: Some test files, unit tests only
- Low coverage: Few or no tests found
- Risk indicator: No tests = high refactoring risk
2c. Find Downstream Effects
For each caller found in step 2a, check what THEY export or provide. Changing your target will affect their behavior.
With dependency tools (preferred): If you have the impact tree from step 2a, depth=2+ already shows transitive downstream effects. Each level of the tree represents one hop of propagation.
With search (fallback):
search_code(
query="<caller_function>",
symbol_name="<caller>*",
use_hybrid_search=True,
smart_context=True
)
Look for:
- Public API exports (appears in
__all__, export, public)
- Used by other modules (appears in other search results)
- External interfaces (API routes, CLI commands, event handlers)
2d. Present the Dependency Map
Format:
Target: [symbol/file name]
Direct usages: N files
- file1.py:123 (in function X)
- file2.py:456 (in class Y)
- ...
Test coverage: M test files
- test_feature.py (unit tests for X)
- test_integration.py (integration tests)
- Coverage assessment: [High/Medium/Low]
Downstream effects:
- Caller A (file3.py) is a public API route → affects external consumers
- Caller B (file4.py) is used by 5 other modules → cascade risk
- ...
Risk assessment: [LOW/MEDIUM/HIGH]
- LOW: 1-3 usages, high test coverage, no public APIs affected
- MEDIUM: 4-10 usages, medium test coverage, internal-only changes
- HIGH: 10+ usages, low test coverage, OR affects public APIs
2e. Branch Based on Impact
Low impact (proceed):
- Show dependency map
- Move directly to Step 3 (generate plan)
Medium impact (confirm scope):
- Show dependency map with details
- Ask: "This affects N files and M tests. Proceed with full refactoring, or want to reduce scope?"
- Wait for user confirmation
High impact (warn + suggest incremental):
- Show dependency map with warning
- Suggest: "High-impact change detected. Consider incremental approach:"
- Phase 1: Add new API alongside old (deprecate, don't remove)
- Phase 2: Migrate callers one-by-one
- Phase 3: Remove old API after full migration
- Ask: "Proceed with full refactoring, incremental migration, or abort?"
Step 3: Generate Refactoring Plan
Produce an ordered list of changes for safe execution.
Ordering principle: Leaf-first dependency order
- Change callees before callers
- Create new code before modifying old
- Update imports after moving code
- Remove old code last
Plan structure:
Refactoring Plan for [target]
============================
Step 1: [Create new structure]
File: [new_file.py]
Action: Create new module with [extracted code]
Reason: Establish new location before migration
Step 2: [Move/copy target code]
File: [new_file.py]
Action: Copy [target function/class] from [old_file.py]
Reason: New code in place, old code still works (safe state)
Step 3: [Update leaf dependencies]
Files: [file1.py, file2.py] (lowest-level callers)
Action: Update imports from old_file to new_file
Reason: Migrate leaf nodes first to prevent cascade failures
Step 4: [Update higher-level dependencies]
Files: [file3.py, file4.py]
Action: Update imports and refactor any API usage changes
Reason: Work up dependency tree
Step 5: [Update tests]
Files: [test_feature.py, test_integration.py]
Action: Update imports, adjust test setup if needed
Reason: Ensure tests pass before removing old code
Step 6: [Remove old code]
File: [old_file.py]
Action: Delete [target function/class]
Reason: Final cleanup after successful migration
Step 7: [Verify]
Action: Run full test suite
Reason: Confirm no regressions
Present to user: "Here's the refactoring plan. Ready to execute step-by-step, or want to adjust?"
Handle adjustments: If user wants changes, update plan and re-present.
Step 4: Execute with Confirmation Gates
For each step in the plan, execute with user confirmation.
For each step:
-
Show what will change:
Step N: [step name]
File: [filename]
Changes:
- [Line X]: Remove: import old_module
- [Line Y]: Add: import new_module
- [Line Z]: Change: old_function() → new_function()
Preview:
[Show before/after diff or code snippet]
-
Request confirmation: "Proceed with this change? (yes/no/skip)"
- yes: Execute the change
- no: Stop execution, return to plan adjustment
- skip: Skip this step, continue to next
-
Make the change: Apply the modification using file editing tools
-
Verify the change:
- If tests are available: "Running tests..."
- Show test results (pass/fail)
- If tests fail: STOP, show failures, ask how to proceed
-
Commit the change (optional): Ask if user wants to commit each step, or commit all at end
After all steps:
Refactoring complete!
Summary:
- N files modified
- M imports updated
- Tests: [PASS/FAIL]
Recommended next steps:
1. Run full test suite: [test command]
2. Manual verification: [areas to check]
3. Commit changes: git add [files] && git commit -m "refactor: [description]"
If any step fails:
- STOP execution immediately
- Show error details (test failures, syntax errors, etc.)
- Ask: "Fix this step and retry, skip this step, or abort refactoring?"
- Wait for user decision
Key Design Principles
Impact analysis is critical: Spend time searching for all dependencies. Missing a usage creates bugs.
Leaf-first ordering: Prevents cascading import failures and broken intermediate states.
User confirmation required: Every code change requires explicit approval. User stays in control.
Test early and often: Suggest running tests after each change, not just at the end. Catch failures early.
Safe intermediate states: After each step, code should still compile/import (even if not fully migrated).
For common search tips (hybrid search, smart_context, symbol filtering), see skills/README.md.
For installation instructions, see skills/README.md.