AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Safe Refactor

skill-terryc21-sitrep-safe-refactor · by Terryc21

Plan refactoring with blast radius analysis, dependency mapping, and rollback strategy. Triggers: "refactor", "safe refactor", "restructure", "rename type", "extract protocol".

No reviews yet
0 installs
18 views
0.0% view→install

Install

$ agentstack add skill-terryc21-sitrep-safe-refactor

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-terryc21-sitrep-safe-refactor)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Safe Refactor? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Safe Refactor

> Quick Ref: Blast radius analysis → dependency mapping → step-by-step plan → verify after each step. Every commit compiles and passes tests. Output: .agents/research/YYYY-MM-DD-refactor-{target}.md

YOU MUST EXECUTE THIS WORKFLOW. Do not just describe it.


Permissions

AskUserQuestion with questions:
[
  {
    "question": "How should Claude handle bash commands, file edits, and writes during this skill run?",
    "header": "Permissions",
    "options": [
      {"label": "Autonomous (Recommended)", "description": "Proceed without per-action approval prompts — destructive actions still require approval"},
      {"label": "Supervised", "description": "Ask for approval before each bash command, file edit, or write"}
    ],
    "multiSelect": false
  }
]

If Autonomous: proceed through all steps without per-action approval prompts. Destructive actions (file deletion, git reset, dropping data) still require explicit user approval. If Supervised: request approval before each bash command, file edit, or write.


Pre-flight: Git Safety Check

git status --short

If uncommitted changes exist:

AskUserQuestion with questions:
[
  {
    "question": "You have uncommitted changes. Commit before proceeding?",
    "header": "Git",
    "options": [
      {"label": "Commit first (Recommended)", "description": "Save current work so you can revert if this skill modifies files"},
      {"label": "Continue without committing", "description": "Proceed — I accept the risk"}
    ],
    "multiSelect": false
  }
]

If "Commit first": Ask for a commit message, stage changed files, and commit. Then proceed.


Step 1: Identify Refactoring Candidates

Scan for files exceeding file size thresholds and display a risk assessment table.

1.1: Find Oversized Files

Check CLAUDE.md for project-specific file size guidelines. If none exist, use these defaults:

| Type | Pattern | Target | Refactor Trigger | |------|---------|--------|-----------------| | Views | *View*.swift | 600 lines | | ViewModels | *ViewModel*.swift | 500 lines | | Managers/Services | *Manager*.swift, *Service*.swift | 600 lines | | Models | *Model*.swift, *+*.swift, *Enums*.swift | 1000 lines |

# First: check CLAUDE.md for project-specific thresholds
Grep pattern="File Size|Split When|lines" path="CLAUDE.md" output_mode="content"
# If found, use those thresholds instead of the defaults above

# Find files exceeding thresholds (exclude Tests/ and generated code)
# Adjust the numeric thresholds below if CLAUDE.md defines different values

# Views over trigger
find Sources -name "*View*.swift" -not -path "*/Tests/*" -exec wc -l {} + | sort -rn | awk '$1 > 600 {print}'

# ViewModels over trigger
find Sources -name "*ViewModel*.swift" -exec wc -l {} + | sort -rn | awk '$1 > 500 {print}'

# Managers/Services over trigger
find Sources \( -name "*Manager*.swift" -o -name "*Service*.swift" \) -not -path "*/Tests/*" -exec wc -l {} + | sort -rn | awk '$1 > 600 {print}'

# Models over trigger
find Sources \( -name "*Model*.swift" -o -name "*Enums*.swift" \) -not -path "*/Tests/*" | xargs wc -l | sort -rn | awk '$1 > 1000 {print}'

1.2: Gather Risk Metrics

For each oversized file, collect:

# For each file: line count, function count, #if os blocks, struct/class/extension blocks
lines=$(wc -l 600 lines)

| # | File | Lines | Over | Blast Radius | Platform Splits | Functions | Tests | Urgency | ROI | Effort |
|---|------|-------|------|-------------|-----------------|-----------|-------|---------|-----|--------|
| 1 | `FileName` | 1289 | 🟡 +289 | 🟢 5 files | 🟡 10 | 1 | Partial | 🟡 High | 🟢 Good | Large |

### ViewModels (trigger: >500 lines)
...

### Managers/Services (trigger: >600 lines)
...

### Models (trigger: >1000 lines)
...

Color thresholds:

| Column | ⚪ Low | 🟢 Medium | 🟡 High | |--------|--------|-----------|---------| | Over | 200 lines | | Blast Radius | 0–2 files | 3–8 files | >8 files | | Platform Splits | 0–3 blocks | 4–8 blocks | >8 blocks |

Urgency (when does this need to happen):

  • 🔴 Critical — actively causing merge conflicts, blocking other work, or growing every sprint
  • 🟡 High — significantly over threshold, frequently edited file, or upcoming feature work will make it worse
  • 🟢 Medium — over threshold but stable, infrequently edited
  • ⚪ Low — barely over threshold, not actively growing

ROI (synthesized judgment):

  • 🟠 Excellent — blocking other work or causing merge conflicts
  • 🟢 Good — significantly over threshold with low blast radius and clear split points
  • 🟡 Marginal — moderate over with high blast radius
  • 🔴 Poor — barely over threshold ("

### 1.2: Document Current State

After reading, note:
- What does this code do?
- How large is it? (lines, methods, properties)
- What patterns does it use currently?

---

## Phase 2: Dependency Mapping

### 2.1: Upstream Dependencies (what target imports/uses)

```bash
# Find imports in the target file
Grep pattern="^import " path="" output_mode="content"

# Find types referenced in the target file
Grep pattern=":\s*\w+Service|:\s*\w+Manager|:\s*\w+Repository" path="" output_mode="content"

Record:

| Dependency | Type | Risk if Changed | |------------|------|-----------------| | NetworkService | Protocol | Low — protocol won't change | | Item | Model | Medium — property access may change |

2.2: Downstream Dependents (what imports/uses target)

# Option A: LSP (most accurate — handles type inference, renames)
LSP operation="findReferences" filePath="" line= character=

# Option B: Grep fallback
# Find all files that reference the target type
Grep pattern="TargetTypeName" glob="**/*.swift" output_mode="files_with_matches"

# Find all usages of the target's public/internal API
Grep pattern="\.targetMethod\(|targetProperty" glob="**/*.swift" output_mode="content"

Record:

| Dependent | Type | Impact if Target Changes | |-----------|------|--------------------------| | ItemDetailView.swift | View | Must update — directly uses view model | | ItemListView.swift | View | Low — only creates the view model | | Tests/ItemViewModelTests.swift | Test | Must update — tests all public API |


Phase 3: Blast Radius

3.1: Calculate Direct, Immediate, and Transitive Impact

# Direct: The target file itself

# Immediate: Files that directly reference the target
Grep pattern="TargetTypeName" glob="**/*.swift" output_mode="files_with_matches"

# Transitive: Files that reference the immediate dependents
# For each immediate file, search for ITS references
Grep pattern="ImmediateTypeName" glob="**/*.swift" output_mode="files_with_matches"

3.2: Summarize Blast Radius

| Risk Level | Files | Description | |------------|-------|-------------| | Direct | 1 | Target file | | Immediate | N | Files that reference target | | Transitive | N | Files that reference immediate dependents |

Total Blast Radius: N files


Phase 4: Safety Checks

Before refactoring, verify:

  • [ ] Code is committed (handled by Pre-flight check)
  • [ ] All usages of the code being changed are understood (from Phase 2)
  • [ ] All existing tests pass (verify if needed)

Phase 5: Choose Strategy

| Approach | When to Use | Risk | |----------|-------------|------| | Parallel Implementation | Large changes, need old code during transition | Low — old code untouched until switch | | Incremental Migration | Medium changes, can do piece by piece | Low — each step verified | | Big Bang | Small changes, isolated code with good test coverage | Medium — all-or-nothing |

Use AskUserQuestion if the best approach isn't obvious.


Phase 6: Step-by-Step Plan

Each step MUST leave the codebase compiling and tests passing.

Example plan format:

Step 1: Extract protocol from ItemDetailViewModel
  Files: ItemDetailViewModel.swift (new protocol), ItemDetailView.swift (type annotation)
  Commit: "Extract ItemDetailViewModelProtocol for testability"
  Verify: Build + tests pass

Step 2: Create MockItemDetailViewModel conforming to protocol
  Files: Tests/Mocks/MockItemDetailViewModel.swift (new)
  Commit: "Add mock view model for testing"
  Verify: Build + tests pass

Step 3: Update ItemDetailView to accept protocol instead of concrete type
  Files: ItemDetailView.swift
  Commit: "Use protocol type in ItemDetailView for dependency injection"
  Verify: Build + tests pass

Phase 7: Verification

After each step:

  • [ ] Build succeeds (no compiler errors or warnings)
  • [ ] All tests pass
  • [ ] Manual smoke test: [specific action to verify]

Phase 8: Rollback Strategy

If something goes wrong:

  • Small steps committed?git revert for the broken step
  • Not yet pushed?git reset --hard
  • Parallel implementation? → Delete new code, old code is untouched

Phase 9: Final Build Verification

After all steps are committed, run a clean build on every platform the project supports.

9.1: Detect Project Platforms

# Check for platform destinations in the Xcode project
grep -r "SUPPORTED_PLATFORMS\|SDKROOT" *.xcodeproj/project.pbxproj | sort -u

# Or check Package.swift for platform targets
grep -i "\.iOS\|\.macOS\|\.watchOS\|\.tvOS\|\.visionOS" Package.swift 2>/dev/null

Common platform indicators:

  • #if os(iOS) / #if os(macOS) in source → multi-platform project
  • SDKROOT = iphoneos + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx" → iOS + macOS
  • Separate targets for watchOS/tvOS/visionOS extensions

9.2: Build Each Platform

Build each detected platform. Use simulator destinations for device platforms:

# iOS
xcodebuild build -scheme  -destination 'platform=iOS Simulator,name=' -quiet

# macOS
xcodebuild build -scheme  -destination 'platform=macOS' -quiet

# watchOS (if applicable)
xcodebuild build -scheme  -destination 'platform=watchOS Simulator,name=' -quiet

# tvOS (if applicable)
xcodebuild build -scheme  -destination 'platform=tvOS Simulator,name=' -quiet

# visionOS (if applicable)
xcodebuild build -scheme  -destination 'platform=visionOS Simulator,name=' -quiet

If a simulator device name fails, list available simulators:

xcrun simctl list devices available | grep -i ""

9.3: Record Results

Record build results in the report:

## Final Build Verification

| Platform | Result |
|----------|--------|
| iOS | ✓ BUILD SUCCEEDED |
| macOS | ✓ BUILD SUCCEEDED |

If any platform fails, investigate — the refactoring may have introduced a platform-specific issue (e.g., missing #if os guard, unavailable API). Fix before generating the report.


Phase 10: Generate Report

Display the refactoring plan and all findings inline, then write to .agents/research/YYYY-MM-DD-refactor-{target}.md:

# Refactoring Plan

**Date:** YYYY-MM-DD
**Target:** [type/file being refactored]
**Strategy:** Incremental / Parallel / Big Bang

## Blast Radius

| Risk Level | Files | Description |
|------------|-------|-------------|
| Direct | 1 | Target file |
| Immediate | N | Files that reference target |
| Transitive | N | Files that reference immediate dependents |
| **Total** | **N** | |

## Step-by-Step Plan

| Step | Change | Files | Commit Message |
|------|--------|-------|----------------|
| 1 | [change] | [files] | "message" |
| 2 | [change] | [files] | "message" |

## Status

| Step | Build | Tests | Verified |
|------|-------|-------|----------|
| 1 | ✓ / ✗ | ✓ / ✗ | ✓ / ✗ |

## Final Build Verification

| Platform | Result |
|----------|--------|
| iOS | ✓ / ✗ |
| macOS | ✓ / ✗ |

Phase 11: Next Target

If Step 1 identified multiple refactoring candidates, offer to continue:

AskUserQuestion with questions:
[
  {
    "question": "Refactoring complete. Would you like to continue to the next candidate from the risk assessment table?",
    "header": "Next target",
    "options": [
      {"label": "Yes, next candidate", "description": "Pick the next target from the table and start Phases 1–10"},
      {"label": "No, done for now", "description": "End the refactoring session"}
    ],
    "multiSelect": false
  }
]

If Yes: Re-display the risk assessment table (updated with the completed target marked ✓), let the user pick the next target, and loop back to Step 2 (gather refactoring details) through Phase 10 (generate report). Each target gets its own commits and report file.

If No: End the session.

Skip this phase if Step 1 found only one candidate or the user specified a single target directly.


Worked Example

User: "Refactor ItemHelper into a protocol so I can mock it in tests"

Phase 1 — Scope:
  Target: ItemHelper.swift (class, 120 lines, 8 methods)
  Reason: Can't mock in tests — concrete class with no protocol
  Desired: ItemHelperProtocol + ItemHelper + MockItemHelper

Phase 2 — Dependencies:
  Upstream: Foundation, SwiftData (Item model)
  Downstream: ItemDetailViewModel (uses 3 methods), ItemListViewModel (uses 1 method),
              2 test files (create ItemHelper directly)

Phase 3 — Blast Radius: 5 files (1 direct + 2 view models + 2 tests)

Phase 4 — Safety: Tests pass, clean git state ✓

Phase 5 — Strategy: Incremental (3 small steps)

Phase 6 — Plan:
  Step 1: Extract ItemHelperProtocol from ItemHelper (keep conformance)
          Commit: "Extract ItemHelperProtocol"
  Step 2: Update view models to use protocol type
          Commit: "Use ItemHelperProtocol in view models"
  Step 3: Create MockItemHelper + update tests
          Commit: "Add MockItemHelper for testing"

Phase 7 — Verify: Build + tests after each step ✓

Phase 9 — Final Build:
  iOS: ✓ BUILD SUCCEEDED
  macOS: ✓ BUILD SUCCEEDED

Refactoring Principles

  1. Never refactor and change behavior in the same commit
  2. Each commit should compile and pass tests
  3. Rename before restructure — rename/move first, then modify
  4. Add tests before refactoring — if coverage is low, add tests first
  5. Small steps — many small commits > one big commit
  6. Reduce as much as safely possible — don't stop at "just under the threshold." Extract along every natural seam (sections, modifiers, helpers, bridge properties, platform-specific code) until no further clean extraction is possible. The threshold is a trigger to start; the goal is the leanest file that still reads clearly.

Troubleshooting

| Problem | Solution | |---------|----------| | Blast radius too large (>20 files) | Consider parallel implementation or incremental approach | | Can't find all dependents | Search for the type name as a string, not just usage patterns | | Tests fail after step | Revert the step, re-analyze, try a smaller change | | Circular dependencies found | Break the cycle first as a separate preparatory step | | Rename causes test failures | Update tests in the same commit as the rename |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.