refactor-safe
Skill63 starsChanged 8 days agoMITView on GitHub
Behaviour-preserving refactoring under a test net — characterization before any move, the eleven seams where a move silently changes behaviour, small reversible steps, and the proof a refactor PR carries. Use when splitting a module, moving a function, or untangling near-duplicate implementations, and before anyone calls a refactor "no behaviour change".
7 other projects use a version of this.
Adopted by
Most recently taken up by
- Markssuave/Markssuave-Agent-skillstheir own version, first seen Nov 8, 2026
- AhmiDarrow/RemedyAItheir own version, first seen Oct 19, 2026
- 0King0P/Claude-Skillstheir own version, first seen Oct 13, 2026
- DailybotHQ/deepworkplan-websitetheir own version, first seen Oct 9, 2026
- aprameyak/coding-skillstheir own version, first seen Oct 2, 2026
- AlpayC/claude-skill-settheir own version, first seen Sep 14, 2026
Other versions7 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 7
- DailybotHQ/deepworkplan-website★ 15same name
- AhmiDarrow/RemedyAI★ 5same name
- aprameyak/coding-skills★ 1same name
- Markssuave/Markssuave-Agent-skills★ 1same name
- 0King0P/Claude-Skills★ 0same name
- AlpayC/claude-skill-set★ 0same name
- ccpowerpack/claude-code-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository56 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .claude/terminals/T0/CLAUDE.mdCLAUDE.md
- .claude/terminals/T1/CLAUDE.mdCLAUDE.md
- .claude/terminals/T2/CLAUDE.mdCLAUDE.md
- .claude/terminals/T3/CLAUDE.mdCLAUDE.md
- api-developerSkill
- architectSkill
- backend-developerSkill
- control-centreSkill
- data-analystSkill
- database-engineerSkill
- debuggerSkill
- excel-reporterSkill
- fabric-referenceSkill
- featureplan-kickoffSkill
- frontend-developerSkill
- horizonSkill
- intelligence-engineerSkill
- monitoring-specialistSkill
- panelSkill
- performance-profilerSkill
- plannerSkill
- pmSkill
- python-optimizerSkill
- quality-engineerSkill
- refactor-safeSkill
- reviewerSkill
- security-engineerSkill
- supabase-expertSkill
- t0-orchestratorSkill
- test-engineerSkill
- vnx-managerSkill
- api-developerSkill
- architectSkill
- backend-developerSkill
- data-analystSkill
- database-engineerSkill
- debuggerSkill
- excel-reporterSkill
- fabric-referenceSkill
- featureplan-kickoffSkill
- frontend-developerSkill
- horizonSkill
- intelligence-engineerSkill
- monitoring-specialistSkill
- performance-profilerSkill
- plannerSkill
- pmSkill
- python-optimizerSkill
- quality-engineerSkill
- reviewerSkill
- security-engineerSkill
- supabase-expertSkill
- t0-orchestratorSkill
- test-engineerSkill
- vnx-managerSkill
The file
We split this skill into the rules it gives an agent
5 rules. 0 are common, 4 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 7 edited versions we read keep these.
4
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 33
Write these four layers first, on the unchanged code, and see all four green.
- Distinctive: line 88
Update patch targets, allowlists and call sites in the same commit as the move.
- Distinctive: line 125
Do not consolidate near-duplicates "while you are there" in a move commit.
- Very specific: line 126
Do not trust a green patch test without assert mock.called.
- Distinctive: line 127
Do not call a solo failure pre-existing, and do not skip the base comparison.
“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Refactor Safe
A refactor changes structure without changing behaviour. That sentence is a claim; this skill is how the claim gets evidence. If you cannot name the test that would fail when the behaviour moves, you are not refactoring — you are rewriting with the old name kept.
Source: the 2026-08-03 six-seat split benchmark. dsflash D.1/D.3/E is the
richest; dspro adds the near-duplicate unification warning; codex adds the
measured-versus-assumed rule.
The behaviour-preservation contract
State the contract before you touch a file:
- Behaviour is the union of observable outputs, side effects, exceptions, log records, exit codes, receipt fields, file paths and call order — not just the return value.
- A move is allowed only when a test that already runs the behaviour stays green, or a characterization test written on the old code stays green after.
- "No behaviour change" is a claim in the PR body with a run behind it. An unrun claim is a guess.
Characterization before any move
Write these four layers first, on the unchanged code, and see all four green. This is a test-only step: no production edit in the same commit.
- Import surface. Assert every public name the consumers import still imports from the module they import it from. ImportError is a loud failure, which makes this the cheapest reliable net.
- Patch binding. For each frequently patched name: patch it, call through
the code path, and
assert mock.called. A patch that hits nothing leaves the test green while the real function runs (see rule 1). - Path resolution. Characterize how data, state and project paths resolve under the env overrides and without them. After a move, assert the resolution chain is unchanged, not that a particular function exists.
- Output shape. Freeze the byte shape of deterministic outputs: token and cost extraction, frontmatter keys, launch command strings, completion footers, lane keys, verification dicts. These become the per-step proof.
The eleven seams
A move can change behaviour silently at each of these. Walk the checklist for every moved symbol.
- Monkeypatch namespace —
patch("old.module.name")stops intercepting once the call site imports the name into a new namespace. - Sibling imports — modules that add their own directory to
sys.pathand import siblings at module scope break when moved into a subpackage. __file__-derived paths — a parent-count that lands onscripts/from the old depth lands somewhere else from the new one; no exception, wrong dir.- Defensive fallback blocks — a
try: import ... except ImportError:fallback defines different behaviour than the real import; move the block with its consumer or the fallback branch disappears. - Logger identity —
logging.getLogger(__name__)changes logger when the module changes; log filters andpatch("module.logger")silently miss. - Call-time name lookup — defaults and globals referenced at call time
(
builder or _default, a module constant) must be imported where they are looked up, not where they are defined. - Cross-module runtime imports — imports done inside a function point at the old module until updated; only the tests that reach that path notice.
- Freeze-test allowlists — an AST guard that permits direct coupling only in listed files must list the new file in the same step.
- Near-duplicates that differ — two similar functions are not one function; check every branch before consolidating (a "cleanup" can add or drop a field).
- Attribute contracts — data passed on a shared object (e.g.
args._x) survives a move only if both readers and writers move together or agree. - CLI entry point — a module run as a script must keep
mainand__main__at the same path; add a--helpsmoke test.
Small reversible steps, and a flag where behaviour must switch
- One commit per step, each independently shippable and revertable. Order from leaf functions (few callers) to orchestrators (everything).
- A pure move needs no flag. When a step changes behaviour — a consolidation, a new default, a renamed field — put it behind a feature flag, keep the old path as the default, and test both paths. Ship the switch separately from the code that it switches.
- Update patch targets, allowlists and call sites in the same commit as the move. A follow-up commit leaves the tree green for the wrong reason.
Two rules this repo learned the hard way
Rule 1 — patch the consumer namespace, not the source module
from X import Y binds Y in the importing module at import time.
patch("X.Y") rebinds only X; the consumer keeps the original. In this repo
three tests patched the source module for years and passed for the wrong
reason, until a CI change made the real function return data. Measured repeat
offenders in the split benchmark: _enrich_instruction (27 patches),
_emit_governance (20), _create_provider_worktree (16). Patch where the name
is looked up, and assert the mock was called.
Rule 2 — a partial test sweep is a different environment
Some tests pass only next to other files; some pass only solo. Measured: the integration directory alone showed 7 failures while the full CI sweep on the same commit was green, and three files that looked order-dependent were actually reading an env var present in one shell and absent in CI. Never call a failure "pre-existing" from a solo or per-directory run. Compare the same sweep composition on the base commit.
What proof a refactor PR carries
- A red run on the old head: the new test fails there and passes after, and the report names the old commit. For a pure move the characterization suite is green on the old head; that green run is the baseline the move must preserve.
- Seam tests written green on the old code first, then kept green across the move. A seam test written after the move proves nothing about the seam.
- Existing tests unchanged unless the refactor deliberately changed the contract; if a test must change, that is a behaviour change and needs a flag.
- The run command and pass/fail counts, not the word "green".
Do not
- Do not consolidate near-duplicates "while you are there" in a move commit.
- Do not trust a green patch test without
assert mock.called. - Do not call a solo failure pre-existing, and do not skip the base comparison.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

