# Hodios paste pack: Refactoring

Everything in Refactoring from Hodios, the open prompt library by Hermes IDE: 8 entries, catalog 2026.1003.0.

Every entry is dedicated to the public domain under CC0 1.0. Copy, change and share them freely, no attribution needed.

Browse and search the library at https://hermes-ide.com/prompts

## How to use

Find an entry below and copy the text inside its block into ChatGPT, claude.ai or any chat. Replace each [PLACEHOLDER] with your own material. Personas, rules and styles work best as custom instructions or project instructions.

## Contents

- Refactoring
  - [Extract a module](#extract-module) (prompt)
  - [Improve naming in code](#improve-naming) (prompt)
  - [Plan a large refactor in safe steps](#plan-large-refactor) (prompt)
  - [Plan splitting a large module](#split-large-module) (prompt)
  - [Reduce code duplication](#reduce-duplication) (prompt)
  - [Remove dead code safely](#remove-dead-code) (prompt)
  - [Simplify a complex function](#simplify-function) (prompt)
  - [Untangle circular dependencies](#untangle-circular-dependencies) (prompt)

---

<a id="extract-module"></a>

## Extract a module

`extract-module` · prompt · Refactoring · https://hermes-ide.com/prompts/extract-module

Moves one responsibility out of a large file or class into its own module in small, test-verified steps, without changing behaviour or the public API. Use when a file does too many things.

````markdown
<context>
Extracting a module is a refactor: the program must behave the same before and after. The hard parts are choosing a boundary that leaves both sides cohesive, and moving the code without breaking callers, creating import cycles or quietly changing behaviour along the way.
</context>

<task>
Extract [RESPONSIBILITY] from [SOURCE] into its own module.
1. **Check the safety net.** Find the tests that cover the code to move. If coverage is thin, stop and report which behaviours need tests first. Do not refactor untested code silently.
2. **Draw the boundary.** List the functions, types and state that belong to the responsibility, and everything they use from the rest of the file. Choose the boundary that minimises what crosses it. If the responsibility shares mutable state with the rest of the file, say how you will pass it explicitly.
3. **Move in small steps**, running the tests after each:
   1. create the new module and move the code unchanged;
   2. import it back into the original file, re-exporting what external callers use so they keep working;
   3. update internal callers to import from the new module;
   4. remove the re-exports only if every caller is in this repository and has been updated. For a public library API, keep them and mark them deprecated.
4. Check for import cycles and fix them by moving the shared piece, not by lazy imports.
5. Run the full test suite, the type checker and the linter.
</task>

<constraints>
- No behaviour changes: no bug fixes, renames of public symbols, signature changes or "improvements" inside moved code. List those under follow-ups instead.
- Keep the diff reviewable: moved code should appear as a move, not a rewrite.
- Do only what was asked. If you notice something else worth changing, mention it in one line at the end instead of changing it.
- Keep the change as small as it can be while still being correct.
- Before saying the work is done, run the check that proves it (tests, build, type check or the command the user gave) and report the real result.
- If you could not run a check, say so plainly and say which one.
</constraints>

<output_format>
## Boundary
What moved, what stayed, and what crosses the boundary, in a short list.
## Steps
The steps you took, each with its test result.
## Diff
The full diff.
## Verification
Test, type-check and lint commands with results.
## Follow-ups
Improvements you noticed but did not make, or "None".
</output_format>
````

---

<a id="improve-naming"></a>

## Improve naming in code

`improve-naming` · prompt · Refactoring · https://hermes-ide.com/prompts/improve-naming

Proposes clearer names for variables, functions, types and modules, explains each rename and applies them without changing behaviour. Use when code reads poorly because of its names.

````markdown
<context>
Names are most of what a reader has to understand code. Bad names come in recognisable kinds: vague (`data`, `info`, `handle`, `process`, `Manager`), misleading (`getUser` that also creates one, `isValid` that returns a list of errors), inconsistent (`customer`, `client` and `account` for the same thing), encoded (`strName`, `arrItems`), wrong in scope (one-letter names that live for 80 lines, or long names for a two-line loop index), and out of step with the business language. A rename is only an improvement if the new name is more accurate, consistent with the codebase and the domain, and applied everywhere without changing behaviour.
</context>

<task>
Improve the names in:

<code>
[CODE]
</code>


1. Read the code and enough of its callers to understand what each name really refers to and does. For functions, check what they actually do, including side effects and return values, not what their name claims.
2. Find names worth changing and classify each: vague, misleading, inconsistent with the rest of the codebase or the glossary, encoded type or scope, wrong length for its scope, or a convention violation (case, prefixes, verb tense for booleans and functions).
3. For each, propose one name following these rules: use the glossary's terms; functions are verbs that say what they do and reveal side effects (`loadOrCreateUser`, not `getUser`); booleans read as yes or no questions (`isExpired`, `hasAccess`); collections are plural; units go in the name when the type does not carry them (`timeoutMs`); length grows with scope; match the existing codebase's conventions over personal preference. If a name is misleading because the function does two things, say so and suggest the split in one line instead of hiding it with a longer name.
4. Separate safe renames from risky ones. Risky renames include public API, exported symbols used by other packages, serialised field names (JSON, database columns, message schemas), configuration keys, names used via reflection, string-based lookups, templates or dependency injection, and anything in a published SDK. Do not apply risky renames; list them with the migration they would need.
5. Apply the safe renames everywhere they are referenced, using the language's refactoring tooling or a careful search that also covers tests, comments and docs in the repo. If the code was pasted rather than in a repo, return the rewritten code.
6. Run the type checker, linter and tests if they exist, and report the real results. Behaviour must not change.
</task>

<constraints>
- Change names only. No logic changes, no reformatting, no reordering, no new abstractions.
- Do not rename for taste: every rename has a reason from step 2. If the existing name is fine, leave it.
- Keep the number of renames proportionate; prefer the 5 to 15 that most improve understanding over renaming everything.
- Do only what was asked. If you notice something else worth changing, mention it in one line at the end instead of changing it.
- Keep the change as small as it can be while still being correct.
- Before saying the work is done, run the check that proves it (tests, build, type check or the command the user gave) and report the real result.
- If you could not run a check, say so plainly and say which one.
</constraints>

<output_format>
## Rename table
Table: old name, new name, kind (variable, function, type, module), problem, why the new name is better. Applied renames only.
## Not renamed
Table: name, proposed name, why it was not applied (public API, serialised, reflection) and the migration it would need. Or "None".
## Changes
For pasted code, the full rewritten code in one fenced block. For a repo, one line per file changed.
## Verification
The checks run and their real results, or which checks could not be run.
</output_format>
````

---

<a id="plan-large-refactor"></a>

## Plan a large refactor in safe steps

`plan-large-refactor` · prompt · Refactoring · https://hermes-ide.com/prompts/plan-large-refactor

Turns a large refactor into small, independently shippable steps that keep the build green, each with a rollback, using patterns like expand-contract. Use for refactors too big for one PR.

````markdown
<context>
Large refactors fail as long-lived branches: they drift from main, conflict with everyone, and land as one unreviewable change. The ones that succeed ship as many small steps, each merged and deployed, with old and new code living side by side until the switch-over. The plan matters more than the code.
</context>

<task>
Plan this refactor: [GOAL]
1. **Map the current state.** Read the code involved and list the components touched, their callers and how many there are, and the tests that cover them. Count call sites rather than guessing.
2. **Choose a strategy** and say why it fits:
   - **branch by abstraction**: put an interface in front of the old code, build the new implementation behind it, switch over, then delete the old one;
   - **expand and contract** (parallel change): add the new form beside the old one, migrate callers in batches, then remove the old form;
   - **strangler fig**: route traffic or calls to the new component piece by piece;
   - a feature flag around the switch-over when it must be reversible at runtime.
3. **Write the steps.** Each step must be mergeable on its own with all tests passing, small enough for one reviewer to review in under an hour, and reversible. For each step give the change, how it is verified, and how it is rolled back.
4. Put the safety net first. If behaviour is not pinned by tests, the first steps add characterization tests.
5. Mark the point of no return, if there is one, such as a data migration or a public API removal, and what must be true before it.
</task>

<constraints>
- Plan only. Do not edit code.
- No step may leave main broken or depend on a later step to compile.
- Base effort and call-site numbers on what you found in the code; mark estimates as estimates.
- If the goal is unclear or seems not worth its cost, say so with the reason, and propose a smaller goal.
- Read the relevant code before making a claim about it. Do not guess what a file, function or config contains.
- If the information you need is not available, say what is missing and how to get it instead of inventing it.
- Separate what you verified from what you inferred. Mark inferences as such.
- When you do not know, say "I don't know" once and state what would settle it.
</constraints>

<output_format>
## Current state
Bullets: the components, call-site counts and test coverage you found.
## Strategy
The chosen pattern and why, in a short paragraph.
## Steps
A numbered table: # | Change | Verified by | Rollback | Size (S, M, L).
## Risks
Bullets: each risk and its mitigation, including the point of no return.
## Done when
A checklist of conditions that prove the refactor is finished, including removal of the old code path.
</output_format>
````

---

<a id="split-large-module"></a>

## Plan splitting a large module

`split-large-module` · prompt · Refactoring · https://hermes-ide.com/prompts/split-large-module

Maps the responsibilities and internal dependencies of an oversized file or class and plans its split into cohesive modules, in small steps that keep tests green. Use before breaking up a god class.

````markdown
<context>
A file grows large because several responsibilities share it, and they are usually tangled through shared private state and helper functions. Splitting by line count or alphabetically produces modules that still depend on each other in both directions. A good split groups code by the data it touches and the reasons it changes, follows the real dependency graph so the new modules have no cycles, and happens in steps small enough that each one can be reviewed, merged and reverted on its own.
</context>

<task>
Plan how to split:
[FILE]


1. Inventory the members (functions, methods, fields, constants, types). For each, record what state it reads and writes, what it calls, and who calls it from outside the file (search the repository if you can).
2. Cluster members into responsibilities by shared data and shared reasons to change. Name each cluster by what it does in the domain, not by technical layer. Flag members that belong to no cluster or to several.
3. Draw the dependency map between clusters, marking each edge with the members that create it. Find cycles and the shared state that causes them.
4. Propose target modules: name, responsibility in one sentence, public surface, and the state it owns. Break each cycle explicitly: move the shared piece to the lower module, pass it as a parameter, or introduce a small interface. Keep the original file as a facade that re-exports the old public API, so callers do not change until a final, optional step.
5. Order the steps so that every step compiles, passes tests and changes one thing: extract leaf clusters (no outgoing dependencies) first, move one cluster per step, update internal references, and remove the facade last. For each step, say what moves, the verification command, and how to revert.
6. Check the safety net: if the tests do not cover a cluster's behaviour, add a step before moving it to add characterization tests for that cluster.
</task>

<constraints>
- This is a plan. Do not perform the moves or rewrite the code.
- No step may change behaviour. Renames, signature changes and bug fixes are separate, later steps if they are needed at all.
- Prefer fewer, cohesive modules over many tiny ones; justify any module with fewer than three members.
- If the file is not available in full, say which parts you could not see and how that limits the plan.
- Read the relevant code before making a claim about it. Do not guess what a file, function or config contains.
- If the information you need is not available, say what is missing and how to get it instead of inventing it.
</constraints>

<output_format>
## Responsibilities
Table: Cluster | Members | State it owns | Reason it changes.
## Dependency map
A Mermaid flowchart of clusters with labelled edges, then the cycles found and how each is broken.
## Target modules
Table: Module (path) | Responsibility | Public surface | Depends on.
## Step plan
Numbered steps. Each: what moves, verification command, revert, approximate diff size.
## Risks
Bullets: dynamic access, reflection, serialization or import side effects that could break, plus gaps in test coverage.
</output_format>
````

---

<a id="reduce-duplication"></a>

## Reduce code duplication

`reduce-duplication` · prompt · Refactoring · https://hermes-ide.com/prompts/reduce-duplication

Finds duplicated logic, separates true duplication from code that only looks alike, and merges only true duplicates behind one well-named function. Use when one fix keeps landing in many places.

````markdown
<context>
Duplication hurts when the copies must change together and someone forgets one of them. Code that only looks alike but changes for different reasons is not duplication. Merging it creates a shared function full of flags that couples unrelated features. The wrong abstraction costs more than the copies did.
</context>

<task>
Reduce duplication in [SCOPE].
1. Find candidate duplicates: repeated blocks, near-identical functions, parallel switch statements, the same validation or formatting written several times.
2. For each group, decide whether it is:
   - **true duplication**: the copies represent the same rule and must change together. Look for evidence: commits that changed several copies at once, or a bug fixed in one copy and not the others;
   - **coincidental**: the copies look alike today but belong to different concepts that will change independently.
3. Merge only true duplication with at least three copies, or two copies that have already drifted and caused a bug. Give the shared code a name that states the rule it represents, and keep its parameters few. If it needs a boolean flag to serve its callers, it is the wrong abstraction.
4. Where copies have already drifted, decide which behaviour is correct. If you cannot tell, do not merge; report the difference as a question.
5. Run the tests after each merge.
</task>

<constraints>
- Leave coincidental duplication alone and say why.
- No behaviour changes. If merging would change one copy's behaviour, stop and report it.
- Prefer a plain function over a class hierarchy, generic or framework hook.
- Do only what was asked. If you notice something else worth changing, mention it in one line at the end instead of changing it.
- Keep the change as small as it can be while still being correct.
- Before saying the work is done, run the check that proves it (tests, build, type check or the command the user gave) and report the real result.
- If you could not run a check, say so plainly and say which one.
</constraints>

<output_format>
## Duplicates
A table: # | Where (`path:line` for each copy) | True or coincidental | Evidence | Action.
## Changes
The diff for the merges you made.
## Verification
Test commands and results. List any drifted copies you left for a decision.
</output_format>
````

---

<a id="remove-dead-code"></a>

## Remove dead code safely

`remove-dead-code` · prompt · Refactoring · https://hermes-ide.com/prompts/remove-dead-code

Finds unused code, flags, endpoints, jobs and dependencies, proves each dead with static and runtime evidence, and removes it or stages a reversible retirement. Use to shrink a codebase.

````markdown
<context>
Dead code costs reading time, build time and false leads when debugging. But "no references found" is not proof of death: code is also reached through reflection, dependency injection, string lookups, routing tables, templates, serialization, plugins, scheduled jobs and callers in other repositories. Some code has no static references to find at all: HTTP endpoints called by other teams or old app versions, flags whose value lives in a flag service, scheduled jobs, config keys and message handlers. Whether they are used is a runtime fact, and "zero calls last week" is weak evidence when a caller runs at month end, at year end, or only on an old mobile release that is still installed. Removing live code is an outage; leaving dead code is only clutter. When in doubt, keep it, or turn it off reversibly first.
</context>

<task>
Find and remove dead code in [SCOPE]. Used outside this repository: unknown.

1. **Find candidates:** unreferenced functions, classes, exports and files; branches that can never run; feature flags that are always on or always off; configuration nobody reads; dependencies nothing imports; and runtime-reachable paths that may be unused: HTTP or RPC endpoints, GraphQL fields, message consumers, scheduled jobs, and tables or columns written but never read. Use the language's tooling where it exists (compiler warnings, unused-export or unused-dependency tools) and text search.
2. **Prove each candidate dead.** Search the whole repository, not only the scope, for the name as a string as well as a symbol. Check dynamic dispatch and reflection, DI containers, routes, templates, config files, build scripts, cron and job definitions, serialization or ORM mappings, and tests.
3. **Classify:**
   - **dead**: no path reaches it, and it is not public API used elsewhere;
   - **likely dead**: no reference found, but it is reachable dynamically or by external callers;
   - **runtime-only**: no static reference, but whether it is used is a runtime fact (endpoints, jobs, flags in a flag service, message handlers, external callers);
   - **alive**: a reference was found.
4. Remove only **dead** items, in small commits grouped by kind, so each can be reverted alone. When a test exists only to exercise dead code, remove the test with it.
5. For **runtime-only** and **likely dead** items, grade the evidence on three rungs: static (no references, including string lookups); runtime (zero use in the evidence sources over a stated window, and whether that window covers monthly, quarterly and yearly cycles and the oldest supported client); ownership (the owning team or known consumers confirmed it is unused). Confidence is high with all three, medium with two, low with one. If no runtime evidence was given, say what to collect; never treat missing evidence as proof of no use.
6. Plan their retirement in stages, one change per stage so each reverts on its own: instrument (a log or metric on every entry to the path, tagged with caller identity) when evidence is missing; announce (deprecation notice, `Deprecation` or `Sunset` headers, changelog) for externally visible paths; soft-disable behind a kill switch, or return 410 Gone with a log line, keeping the code for a waiting period that covers the longest usage cycle; delete code, tests, config and flag definitions together, then now-unused dependencies in their own change; drop tables or columns only after the code that wrote them is gone and a backup exists. Order the items so that retiring one never breaks another that is still live.
7. Run the build, type checker, linter and tests after the removal.
</task>

<constraints>
- If unknown is `yes` or `unknown`, treat exported or public symbols as **likely dead** at most, and do not remove them. Code that only runtime evidence can prove unused, such as endpoints, jobs and flags, needs a staged retirement, not a deletion.
- Only high-confidence items may be planned for deletion; medium items go to soft-disable; low items need more evidence. Nothing externally reachable is deleted without a soft-disable stage first.
- Name the exact evidence for each staged item: the query or log search, the window and the count. Do not invent numbers; write "missing" when evidence is missing.
- Write the staged retirement as a plan with change boundaries; do not make those changes unless asked.
- Never remove code just because it is old, commented as deprecated, or unused in tests only.
- Do not refactor or reformat code that stays.
- Do only what was asked. If you notice something else worth changing, mention it in one line at the end instead of changing it.
- Keep the change as small as it can be while still being correct.
- Before saying the work is done, run the check that proves it (tests, build, type check or the command the user gave) and report the real result.
- If you could not run a check, say so plainly and say which one.
</constraints>

<output_format>
## Removed
A table: Item | Where | Evidence it was dead.
## Kept
A table: Item | Where | Why it was kept (likely dead or alive, and the reference found). Or "None".
## Staged retirement
A table: Item | Type | Static | Runtime (window, count) | Ownership | Confidence | Action (soft-disable / collect evidence / keep), then numbered stages with timing relative to start (week 0, week 4…), the signal that allows the next stage, and how to roll each stage back. Or "None".
## Verification
Build, type-check, lint and test commands with results.
</output_format>
````

---

<a id="simplify-function"></a>

## Simplify a complex function

`simplify-function` · prompt · Refactoring · https://hermes-ide.com/prompts/simplify-function

Rewrites a hard-to-follow function into a clearer one with identical behaviour, using guard clauses, named steps and simpler conditions, verified by tests. Use on long or deeply nested code.

````markdown
<context>
A function is hard to change when a reader has to hold too much in mind at once: deep nesting, flags that switch behaviour, long stretches doing several jobs, conditions that need a truth table. Simplifying means removing that load while keeping every observable behaviour, including the odd edge cases callers may depend on.
</context>

<task>
Simplify [TARGET].
1. Read the function and its callers. Write down its observable behaviour: return values, errors raised, side effects and their order, and edge cases (empty, null, boundaries).
2. Make sure tests pin that behaviour. If they do not, add focused tests for the uncovered paths first, and run them against the original code.
3. Name what makes it hard to read, specifically: nesting depth, a boolean flag argument, mixed levels of abstraction, duplicated branches, a variable reused for different meanings.
4. Apply the smallest set of changes that addresses those points. Typical moves:
   - guard clauses and early returns instead of nested conditions;
   - extract a well-named helper for each distinct step;
   - split a flag argument into two functions when the flag selects different behaviour;
   - simplify boolean expressions and name complex conditions;
   - replace a long if/else chain over one value with a lookup table, when that is clearer.
5. Run the tests after each change. Then measure the before and after: lines, maximum nesting depth and number of branches, by counting rather than estimating.
</task>

<constraints>
- Behaviour stays identical, including error types and messages, side-effect order and edge-case results. If you believe an edge case is a bug, keep it and report it.
- Do not change the function's signature or public name unless asked.
- Prefer clear over clever: no dense one-liners, no new abstractions with a single use.
- Match the surrounding code's style and idioms.
- Do only what was asked. If you notice something else worth changing, mention it in one line at the end instead of changing it.
- Keep the change as small as it can be while still being correct.
- Before saying the work is done, run the check that proves it (tests, build, type check or the command the user gave) and report the real result.
- If you could not run a check, say so plainly and say which one.
</constraints>

<output_format>
## What made it hard
Two to four bullets.
## Diff
The diff, including any tests added first.
## Behaviour check
The test command and result, and the tests added to pin behaviour.
## Before and after
A table: Metric | Before | After, for lines, maximum nesting depth and branches.
</output_format>
````

---

<a id="untangle-circular-dependencies"></a>

## Untangle circular dependencies

`untangle-circular-dependencies` · prompt · Refactoring · https://hermes-ide.com/prompts/untangle-circular-dependencies

Finds circular dependencies between modules and plans breaking each cycle with interfaces, inversion or extraction in safe steps. Use when import cycles cause build errors or tangled code.

````markdown
<context>
A dependency cycle means two or more modules cannot be understood, tested, built or deployed apart. Cycles cause import-order bugs (a value undefined at load time), slow incremental builds and modules that can never be extracted. The fix is rarely "move the import inside the function"; that hides the cycle. The real fix depends on why the edge exists: a shared type that belongs lower down, a callback that should be inverted, a misplaced function, or two modules that are really one. The right break is the edge that is least essential, chosen so that dependencies point from volatile, high-level code toward stable, low-level code.
</context>

<task>
Analyse these dependencies:
<dependency_info>
[DEPENDENCY_INFO]
</dependency_info>

1. List every cycle as a path (`a → b → c → a`). If the input is a large graph, list the strongly connected components and the shortest cycles inside each. If you can read the repository, confirm each edge by finding the import and what it uses; otherwise mark edges you could not confirm.
2. For each edge in a cycle, record what crosses it: types only, a function call, a constant, a class to instantiate, a registry or event. Note whether the use is at load time (top-level) or at call time.
3. Diagnose each cycle and pick a technique:
   - **Move down:** a shared type, constant or pure helper used by both belongs in a lower module (often a new `types`, `contracts` or `shared` module). Keep that module free of dependencies on its users.
   - **Invert:** the lower module calls back into the higher one. Define an interface or callback in the lower module and have the higher module provide the implementation (dependency injection, a port, an event).
   - **Move the function:** one function is in the wrong module; moving it removes the edge.
   - **Merge:** the modules change together and share invariants; merge them, then split along a better seam later if needed.
   - **Extract:** both depend on a cohesive piece that should become its own module.
   State why you chose the technique over the others, and which direction the dependency will point afterwards.
4. Order the work so each step compiles, passes tests and could ship alone. Break the cheapest, most-shared edges first. For each step give the files touched, the change, and a small code sketch in the project's language for non-obvious moves.
5. Propose a guardrail that fails CI if a cycle returns: a rule for the project's tool (dependency-cruiser `no-circular`, import-linter contracts, ArchUnit, eslint `import/no-cycle`, Go's compiler already forbids package cycles) or a layered-architecture rule that also fixes the intended direction.
</task>

<constraints>
- Do not propose lazy or in-function imports, `require` inside functions, or forward-declaration tricks as the fix. Mention them only as a temporary unblocker, labelled as such.
- Type-only imports (TypeScript `import type`, Python `if TYPE_CHECKING:`) are a legitimate fix when the edge carries types and nothing else: they remove the runtime cycle and its load-order bugs. Say that the design-level coupling remains, and whether the cycle tool will still report the edge (check its type-only setting).
- Keep behaviour identical; this is a refactor. Flag any step that could change load order or initialisation side effects.
- Do not rename or restructure beyond what breaking the cycles needs.
- Base the analysis on the edges given or read; never invent modules or imports.
- Do only what was asked. If you notice something else worth changing, mention it in one line at the end instead of changing it.
- Keep the change as small as it can be while still being correct.
- Separate what you verified from what you inferred. Mark inferences as such.
- When you do not know, say "I don't know" once and state what would settle it.
</constraints>

<output_format>
## Cycles found
Numbered cycle paths, with what crosses each edge and whether it is load-time or call-time.
## Diagnosis
Per cycle: the edge to break, the technique, why, and the dependency direction afterwards. Include a Mermaid `graph LR` showing before and after for the largest cycle.
## Break plan
Numbered steps, each independently shippable: files, change, code sketch where needed, how to verify.
## Guardrail
The CI rule or configuration, in a fenced block.
## Questions
Anything you need to confirm, or "None".
</output_format>
````
