continuous-refactoring 0.1.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/.gitignore +2 -0
  2. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/PKG-INFO +107 -24
  3. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/README.md +106 -23
  4. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/pyproject.toml +1 -1
  5. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/cli.py +298 -16
  6. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/commit_messages.py +6 -2
  7. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/config.py +33 -1
  8. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/decisions.py +15 -20
  9. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/effort.py +45 -8
  10. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/failure_report.py +68 -2
  11. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/git.py +1 -1
  12. continuous_refactoring-0.3.0/src/continuous_refactoring/log_mirroring.py +11 -0
  13. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/loop.py +351 -77
  14. continuous_refactoring-0.3.0/src/continuous_refactoring/migration_cli.py +701 -0
  15. continuous_refactoring-0.3.0/src/continuous_refactoring/migration_consistency.py +528 -0
  16. continuous_refactoring-0.3.0/src/continuous_refactoring/migration_tick.py +950 -0
  17. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/phases.py +13 -5
  18. continuous_refactoring-0.3.0/src/continuous_refactoring/planning.py +1223 -0
  19. continuous_refactoring-0.3.0/src/continuous_refactoring/planning_publish.py +688 -0
  20. continuous_refactoring-0.3.0/src/continuous_refactoring/planning_state.py +1037 -0
  21. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/prompts.py +44 -7
  22. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/refactor_attempts.py +86 -18
  23. continuous_refactoring-0.3.0/src/continuous_refactoring/review_cli.py +296 -0
  24. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/routing.py +40 -21
  25. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/routing_pipeline.py +170 -70
  26. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/scope_candidates.py +27 -18
  27. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/scope_expansion.py +51 -15
  28. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/targeting.py +15 -18
  29. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/conftest.py +76 -24
  30. continuous_refactoring-0.3.0/tests/test_cli_init_taste.py +706 -0
  31. continuous_refactoring-0.3.0/tests/test_cli_migrations.py +1485 -0
  32. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_cli_review.py +113 -10
  33. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_cli_taste_warning.py +74 -6
  34. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_cli_upgrade.py +56 -62
  35. continuous_refactoring-0.3.0/tests/test_cli_version.py +39 -0
  36. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_commit_messages.py +10 -0
  37. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_config.py +173 -20
  38. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_continuous_refactoring.py +8 -1
  39. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_decisions.py +85 -0
  40. continuous_refactoring-0.3.0/tests/test_effort.py +143 -0
  41. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_failure_report.py +216 -7
  42. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_focus_on_live_migrations.py +448 -30
  43. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_git.py +60 -29
  44. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_loop_migration_tick.py +872 -38
  45. continuous_refactoring-0.3.0/tests/test_migration_consistency.py +305 -0
  46. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_no_driver_branching.py +8 -18
  47. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_phases.py +133 -6
  48. continuous_refactoring-0.3.0/tests/test_planning.py +1498 -0
  49. continuous_refactoring-0.3.0/tests/test_planning_publish.py +611 -0
  50. continuous_refactoring-0.3.0/tests/test_planning_state.py +873 -0
  51. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_prompts.py +222 -0
  52. continuous_refactoring-0.3.0/tests/test_refactor_attempts.py +166 -0
  53. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_routing.py +90 -0
  54. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_run.py +829 -128
  55. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_run_once.py +128 -18
  56. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_scope_candidates.py +29 -10
  57. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_scope_expansion.py +136 -0
  58. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_scope_loop_integration.py +211 -6
  59. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_scope_selection.py +28 -0
  60. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_targeting.py +14 -0
  61. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_taste_interview.py +38 -6
  62. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_taste_refine.py +3 -5
  63. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_taste_upgrade.py +16 -10
  64. continuous_refactoring-0.1.0/src/continuous_refactoring/migration_tick.py +0 -468
  65. continuous_refactoring-0.1.0/src/continuous_refactoring/planning.py +0 -588
  66. continuous_refactoring-0.1.0/src/continuous_refactoring/review_cli.py +0 -136
  67. continuous_refactoring-0.1.0/tests/test_cli_init_taste.py +0 -288
  68. continuous_refactoring-0.1.0/tests/test_effort.py +0 -54
  69. continuous_refactoring-0.1.0/tests/test_planning.py +0 -579
  70. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/LICENSE +0 -0
  71. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/__init__.py +0 -0
  72. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/__main__.py +0 -0
  73. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/agent.py +0 -0
  74. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/artifacts.py +0 -0
  75. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/migration_manifest_codec.py +0 -0
  76. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/src/continuous_refactoring/migrations.py +0 -0
  77. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/fixtures/claude_stream_json/selection.stdout.log +0 -0
  78. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_claude_stream_json.py +0 -0
  79. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_e2e.py +0 -0
  80. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_main_entrypoint.py +0 -0
  81. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_migrations.py +0 -0
  82. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_prompts_scope_selection.py +0 -0
  83. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_run_once_regression.py +0 -0
  84. {continuous_refactoring-0.1.0 → continuous_refactoring-0.3.0}/tests/test_wake_up.py +0 -0
@@ -1,4 +1,6 @@
1
1
  .scratchpad/
2
+ tmpdir/
3
+ .pytest_cache/
2
4
 
3
5
  # Byte-compiled / optimized / DLL files
4
6
  __pycache__/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: continuous-refactoring
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: Continuous refactoring loop for AI coding agents
5
5
  Project-URL: Repository, https://github.com/bigH/continuous-refactoring
6
6
  Project-URL: Issues, https://github.com/bigH/continuous-refactoring/issues
@@ -23,16 +23,43 @@ Description-Content-Type: text/markdown
23
23
 
24
24
  # continuous-refactoring
25
25
 
26
+ [![GitHub repo](https://img.shields.io/badge/github-repo-green)](https://github.com/bigH/continuous-refactoring)
27
+ [![PyPI](https://img.shields.io/pypi/v/continuous-refactoring.svg)](https://pypi.org/project/continuous-refactoring/)
28
+ [![Tests](https://github.com/bigH/continuous-refactoring/actions/workflows/test.yml/badge.svg)](https://github.com/bigH/continuous-refactoring/actions/workflows/test.yml)
29
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bigH/continuous-refactoring/blob/main/LICENSE)
30
+
26
31
  Small, test-gated cleanup commits by an AI coding agent.
27
32
 
28
33
  Think of it as a supervised janitor loop: the agent proposes a cleanup, your tests decide if it stays.
29
34
 
35
+ Here's [an article](https://artisincode.com/essays/how-i-use-unspent-tokens/) I wrote about it.
36
+
30
37
  ## Install
31
38
 
39
+ Try it without installing:
40
+
41
+ ```bash
42
+ uvx continuous-refactoring --help
43
+ ```
44
+
45
+ Or install it with [uv](https://docs.astral.sh/uv/guides/tools/):
46
+
32
47
  ```bash
33
48
  uv tool install continuous-refactoring
34
49
  ```
35
50
 
51
+ Or with [pipx](https://pypa.github.io/pipx/):
52
+
53
+ ```bash
54
+ pipx install continuous-refactoring
55
+ ```
56
+
57
+ Or with pip:
58
+
59
+ ```bash
60
+ pip install continuous-refactoring
61
+ ```
62
+
36
63
  For a checkout:
37
64
 
38
65
  ```bash
@@ -67,15 +94,18 @@ continuous-refactoring run \
67
94
  --max-attempts 2
68
95
  ```
69
96
 
70
- That keeps sweeping targets until it runs out, hits your caps, or starts failing.
97
+ That runs up to 10 refactor actions, then stops sooner if the finite target file
98
+ runs out or the loop starts failing. Use `run --focus-on-live-migrations` when
99
+ you want the loop to work only on eligible live migrations; it bypasses target
100
+ selection and `--max-refactors`.
71
101
 
72
102
  ## What it does
73
103
 
74
- - Resolves a target from `--targets`, `--globs`, `--extensions`, or `--paths`, with optional natural-language scoping via `--scope-instruction`.
104
+ - Resolves each source action from `--targets`, `--globs`, `--extensions`, or `--paths`, with optional natural-language scoping via `--scope-instruction`.
75
105
  - Runs the agent with a refactoring prompt + your "taste" guidelines.
76
106
  - Runs your validation command (default: `uv run pytest`).
77
107
  - If green and there's a diff, it commits locally and leaves the branch for you to inspect.
78
- - Repeats until it runs out of targets, hits the retry budget, or stacks too many failures.
108
+ - Repeats until it spends the action budget, exhausts a finite target file, hits the retry budget, or stacks too many failures.
79
109
 
80
110
  ## Requirements
81
111
 
@@ -89,6 +119,8 @@ That keeps sweeping targets until it runs out, hits your caps, or starts failing
89
119
  ```bash
90
120
  # 1. Register the repo (creates a project dir under ~/.local/share/continuous-refactoring)
91
121
  continuous-refactoring init
122
+ # Or keep project taste in the repo:
123
+ continuous-refactoring init --in-repo-taste
92
124
 
93
125
  # 2. (Optional) Write your refactoring taste — either edit the file, have an agent interview you,
94
126
  # or refine an existing draft collaboratively
@@ -113,13 +145,18 @@ continuous-refactoring run \
113
145
 
114
146
  | Command | What it does |
115
147
  |---|---|
116
- | `init` | Registers this directory as a project, creates a default `taste.md`, and can store `--live-migrations-dir`. |
148
+ | `init` | Registers this directory as a project, creates a default `taste.md`, and can store `--live-migrations-dir` or `--in-repo-taste`. |
117
149
  | `taste` | Prints the active taste file path. Add `--interview` to have an agent author it, `--refine` to iteratively improve an existing taste doc, `--upgrade` to refresh stale taste dimensions, `--global` for the shared file, and `--force` to let `--interview` overwrite custom content after writing a `.bak`. |
118
150
  | `run-once` | Single pass on one resolved target. No retry. If there is a diff and validation passes, it commits locally and prints the diffstat. |
119
- | `run` | The loop. Iterates targets, retries on failure, and commits successful targets locally. |
151
+ | `run` | The loop. Iterates refactor actions, retries on failure, and commits successful changes locally. Add `--focus-on-live-migrations` to bypass targeting and work only on eligible live migrations. |
120
152
  | `upgrade` | Checks that the global config manifest is current, rewrites it idempotently, and warns if the global taste file is stale. |
121
- | `review list` | Lists migrations flagged for human review (`awaiting_human_review`). |
122
- | `review perform <migration>` | Starts an interactive agent session to resolve a flagged migration's review. Requires `--with`, `--model`, and `--effort`. |
153
+ | `migration list` | Lists visible migrations. Add `--status <status>` or `--awaiting-review` to filter. |
154
+ | `migration doctor <slug-or-path>` | Validates one visible migration's consistency. |
155
+ | `migration doctor --all` | Validates every visible migration plus internal transaction state. |
156
+ | `migration review <slug-or-path>` | Starts staged review for a migration awaiting human review. Requires `--with`, `--model`, and `--effort`. |
157
+ | `migration refine <slug-or-path>` | Records feedback for a planning or unexecuted ready migration and runs one staged planning revision. Requires `--message <text>` or `--file <path>`, plus `--with`, `--model`, and `--effort`; add `--show-agent-logs` to mirror the planning agent. |
158
+
159
+ Legacy `review list` and `review perform <migration>` remain compatibility aliases; prefer `migration list --awaiting-review` and `migration review`.
123
160
 
124
161
  ## Targeting / Useful flags
125
162
 
@@ -130,21 +167,46 @@ Target resolution is first-match-wins:
130
167
 
131
168
  These flags are not mutually exclusive, but only the highest-priority populated source is used.
132
169
 
133
- - `--targets path/to/targets.jsonl` — explicit list; one JSON object per line with `description`, `files`, optional `scoping`, `model-override`, `effort-override`. Effort overrides use `low`, `medium`, `high`, or `xhigh`.
134
- - `--globs 'src/**/*.py:tests/**/*.py'` — colon-separated globs; each matched file becomes its own target.
135
- - `--extensions .py,.ts` — shorthand that expands to `**/*.py`, `**/*.ts`; each matched file becomes its own target.
136
- - `--paths a.py:b.py` — literal paths, all treated as one target.
137
- - `--scope-instruction "clean up the auth module"` — extra free-text scoping. If file-based targeting resolves nothing, this becomes the useful fallback context.
170
+ - `--targets path/to/targets.jsonl` — explicit finite list; one JSON object per line with `description`, `files`, optional `scoping`, `model-override`, `effort-override`. Effort overrides use `low`, `medium`, `high`, or `xhigh`. If `--max-refactors` is omitted, `run` processes the file once and stops.
171
+ - `--globs 'src/**/*.py:tests/**/*.py'` — colon-separated globs matched once against tracked files from `git ls-files`; each refactor action samples one matched file, so files can repeat.
172
+ - `--extensions .py,.ts` — shorthand that expands to `**/*.py`, `**/*.ts` against tracked files from `git ls-files`; each refactor action samples one matched file, so files can repeat.
173
+ - `--paths a.py:b.py` — literal user-provided paths, all treated as one grouped target; each refactor action reuses that group.
174
+ - `--scope-instruction "clean up the auth module"` — extra free-text scoping. If selected file patterns resolve nothing, this becomes the useful fallback context.
175
+
176
+ If `--globs` or `--extensions` match no tracked files and there is no
177
+ `--scope-instruction`, `run` completes successfully with zero refactor actions.
178
+ `--paths` is literal input and is not filtered through `git ls-files`.
138
179
 
139
- If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`, then `run` and `run-once` require `--scope-instruction`.
180
+ If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`,
181
+ then `run` and `run-once` require `--scope-instruction`; the driver still
182
+ random-samples tracked files from `git ls-files` for each action and uses the
183
+ scope text as context for that target.
140
184
 
141
185
  ### Migrations & taste flags
142
186
 
143
187
  - `init --live-migrations-dir PATH` — enables the larger-refactoring workflow for this project. The path is stored repo-relative in the project registry and created if missing.
188
+ - `init --in-repo-taste [PATH]` — stores this project's taste file in the repo and remembers the repo-relative path. Defaults to `.continuous-refactoring/taste.md`; re-run `init --in-repo-taste ...` to choose a different path.
189
+ - `migration list` — shows visible migrations; `--awaiting-review` narrows to human-review handoffs.
190
+ - `migration doctor <slug-or-path>` / `migration doctor --all` — read-only consistency checks. Doctor reports problems; it does not repair them.
191
+ - `migration review <slug-or-path> --with ... --model ... --effort ...` — resolves an `awaiting_human_review` migration through a staged workspace.
192
+ - `migration refine <slug-or-path> (--message <text>|--file <path>) --with ... --model ... --effort ... [--show-agent-logs]` — adds user feedback to a planning or unexecuted ready migration and resumes planning through the `revise` step when reopening ready work.
144
193
  - `taste --refine` — opens a collaborative editing session for the taste file. The agent keeps refining until you tell it to write, then the session ends automatically after the settled write.
145
194
  - `taste --upgrade` — re-interviews for taste dimensions added since your last version. No-op when already current; use `taste --refine` if you want to rework the doc anyway.
146
195
  - `taste --force` — only applies to `--interview`; it allows a customized taste file to be overwritten after backing it up to `taste.md.bak`.
147
196
 
197
+ Canonical migration commands:
198
+
199
+ ```bash
200
+ continuous-refactoring migration list
201
+ continuous-refactoring migration list --status planning
202
+ continuous-refactoring migration list --awaiting-review
203
+ continuous-refactoring migration doctor <slug-or-path>
204
+ continuous-refactoring migration doctor --all
205
+ continuous-refactoring migration review <slug-or-path> --with codex --model gpt-5 --effort high
206
+ continuous-refactoring migration refine <slug-or-path> --message "split the risky phase" --with codex --model gpt-5 --effort high
207
+ continuous-refactoring migration refine <slug-or-path> --file feedback.md --with codex --model gpt-5 --effort high
208
+ ```
209
+
148
210
  ### Shared `run` / `run-once` flags
149
211
 
150
212
  - `--with`, `--model` — required agent backend/model selection.
@@ -159,10 +221,11 @@ If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`, the
159
221
 
160
222
  ### `run`-only flags
161
223
 
162
- - `--max-attempts N` — per-target retry budget. `1` = no retry, `0` = unlimited (which means permanently broken targets will never give up).
163
- - `--max-refactors N` — cap the number of targets per run. Required unless you use `--targets`.
164
- - `--max-consecutive-failures N` — bail after N targets fail in a row. Default 3.
165
- - `--sleep SECONDS` — pause between completed targets. Useful when you want a long batch without hammering the repo or your agent budget.
224
+ - `--max-attempts N` — per-action retry budget. `1` = no retry, `0` = unlimited (which means permanently broken actions will never give up).
225
+ - `--max-refactors N` — cap the number of refactor actions per run. Required unless you use `--targets` or `--focus-on-live-migrations`.
226
+ - `--focus-on-live-migrations` — bypass target selection and `--max-refactors`; iterate eligible live migrations until they are done, deferred, blocked, or the failure budget trips.
227
+ - `--max-consecutive-failures N` — bail after N actions fail in a row. Default 3.
228
+ - `--sleep SECONDS` — pause between completed actions. Useful when you want a long batch without hammering the repo or your agent budget.
166
229
  - `--commit-message-prefix TEXT` — subject prefix for successful refactor or migration-plan commits. Default `continuous refactor`.
167
230
 
168
231
  ## Safety behaviors
@@ -179,22 +242,36 @@ If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`, the
179
242
  Each run writes to `$TMPDIR/continuous-refactoring/<run-id>/`:
180
243
 
181
244
  - `summary.json` — rolling status, counts, per-attempt stats
182
- - `events.jsonl` — structured event log
245
+ - `events.jsonl` — structured event log with call roles such as `classify`,
246
+ `planning.<step>`, `phase.ready-check`, `phase.execute`, and
247
+ `phase.validation`
183
248
  - `run.log` — human-readable log
184
249
  - `attempt-NNN/[retry-NN/]refactor/` — per-attempt agent + test stdout/stderr
250
+ - `baseline/initial/` — baseline validation stdout/stderr before work starts
251
+ - `classify/` — classifier agent stdout/stderr
252
+ - `scope-expansion/` — scope candidates, selection, and bypass reason
253
+ - `attempt-NNN/[retry-NN/]planning/<step>/` — planning agent stdout/stderr for
254
+ migration planning steps
255
+ - `phase-ready-check/` — phase precondition agent stdout/stderr
256
+ - `attempt-NNN/[retry-NN/]phase-execute/` — phase agent and validation logs
257
+ - `migration-probes/action-NNN/` — migration probe logs during normal `run`
258
+ actions, including planning, phase ready-checks, and phase execution
185
259
 
186
260
  Mixed-effort runs are auditable: summaries and call events record the default effort, max allowed effort, requested effort, effective effort, source, and whether the request was capped.
187
261
 
188
- The path prints at startup. Grep it when something goes sideways.
262
+ The path prints at startup. Grep it when something goes sideways. Failed
263
+ non-commit decisions also write durable XDG snapshots under the project failure
264
+ directory, usually
265
+ `~/.local/share/continuous-refactoring/projects/<uuid>/failures/`.
189
266
 
190
267
  ## Taste files
191
268
 
192
269
  The taste file is a short bullet list of your refactoring preferences. It gets injected into every agent prompt.
193
270
 
194
- - Project taste: `~/.local/share/continuous-refactoring/projects/<uuid>/taste.md`
271
+ - Project taste: `~/.local/share/continuous-refactoring/projects/<uuid>/taste.md`, or the repo-local path chosen with `init --in-repo-taste [PATH]`
195
272
  - Global taste: `~/.local/share/continuous-refactoring/global/taste.md`
196
273
 
197
- Project taste wins over global. Use `taste --interview` to bootstrap one, `taste --refine` to rework it with an agent, or edit the file directly any time.
274
+ Project taste wins over global. Use `taste` to print the active path, `taste --interview` to bootstrap one, `taste --refine` to rework it with an agent, or edit the file directly any time.
198
275
 
199
276
  ## Larger refactorings
200
277
 
@@ -213,7 +290,7 @@ This tells the CLI where to store migration artifacts. The path is repo-relative
213
290
  Each `run` / `run-once` tick now checks for eligible migration work before falling back to single-commit cleanups:
214
291
 
215
292
  1. **Classify** — a classifier agent reads the target and decides: `cohesive-cleanup` (one-shot path) or `needs-plan` (migration path).
216
- 2. **Plan** — for `needs-plan` targets, a six-stage planning workflow runs: generate approaches pick best expand into phases → review revise final review. Artifacts land under `<live-migrations-dir>/<migration-name>/`.
293
+ 2. **Plan** — for `needs-plan` targets, each automation action runs exactly one planning step: approaches, pick-best, expand, review, optional revise/review-2, then final-review. Accepted steps update `.planning/state.json`, store stdout under `.planning/stages/`, and publish through a staged transaction. Failed current-step output stays in run artifacts and is not resume input.
217
294
  3. **Execute** — each phase is a self-contained unit of work. The tick picks the oldest eligible migration, checks whether its current phase precondition is satisfied, and executes it on the current branch. Phase completion is judged against the phase file's `## Definition of Done`; commit message identifies the migration as `migration/<name>/<phase-file>.md`.
218
295
 
219
296
  ### Migration directory layout
@@ -222,14 +299,20 @@ Each `run` / `run-once` tick now checks for eligible migration work before falli
222
299
  <live-migrations-dir>/
223
300
  <migration-name>/
224
301
  manifest.json # status, phases, wake-up schedule
302
+ .planning/
303
+ state.json # durable planning cursor and accepted step refs
304
+ stages/ # accepted planning stdout, suffixed on repeats
225
305
  plan.md # the expanded plan
226
306
  approaches/ # candidate approaches considered during planning
227
307
  phase-1-<name>.md # per-phase specification
228
308
  phase-2-<name>.md
229
309
  ...
310
+ __transactions__/ # internal staged publish state
230
311
  __intentional_skips__/ # migrations rejected at final review
231
312
  ```
232
313
 
314
+ Do not edit `.planning/` or `__transactions__/` by hand. Use `migration doctor` when the shape looks wrong.
315
+
233
316
  ### Wake-up rules
234
317
 
235
318
  Migrations don't run on every tick. The scheduler now separates **activity** from
@@ -263,7 +346,7 @@ Before executing a phase, a ready-check agent verifies that the current phase pr
263
346
 
264
347
  - **ready: yes** — phase executes; on green tests, the phase is marked done, any prior deferral markers are cleared, and the migration advances immediately to the next phase.
265
348
  - **ready: no** — manifest activity is bumped, a retry cooldown is started, and a future `wake_up_on` is recorded when needed; the tick moves on.
266
- - **ready: unverifiable** — the migration is flagged `awaiting_human_review` and put on cooldown. Automated migration ticks skip flagged migrations until review clears the flag. Use `review list` to find it and `review perform <migration> --with ... --model ... --effort ...` to resolve it interactively.
349
+ - **ready: unverifiable** — the migration is flagged `awaiting_human_review` and put on cooldown. Automated migration ticks skip flagged migrations until review clears the flag. Use `migration list --awaiting-review` to find it and `migration review <slug-or-path> --with ... --model ... --effort ...` to resolve it interactively.
267
350
 
268
351
  Human-facing migration references use the relative phase spec path, for example `phase-2-failure-report.md`. The manifest cursor stores the phase `name`, not a numeric index.
269
352
 
@@ -1,15 +1,42 @@
1
1
  # continuous-refactoring
2
2
 
3
+ [![GitHub repo](https://img.shields.io/badge/github-repo-green)](https://github.com/bigH/continuous-refactoring)
4
+ [![PyPI](https://img.shields.io/pypi/v/continuous-refactoring.svg)](https://pypi.org/project/continuous-refactoring/)
5
+ [![Tests](https://github.com/bigH/continuous-refactoring/actions/workflows/test.yml/badge.svg)](https://github.com/bigH/continuous-refactoring/actions/workflows/test.yml)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bigH/continuous-refactoring/blob/main/LICENSE)
7
+
3
8
  Small, test-gated cleanup commits by an AI coding agent.
4
9
 
5
10
  Think of it as a supervised janitor loop: the agent proposes a cleanup, your tests decide if it stays.
6
11
 
12
+ Here's [an article](https://artisincode.com/essays/how-i-use-unspent-tokens/) I wrote about it.
13
+
7
14
  ## Install
8
15
 
16
+ Try it without installing:
17
+
18
+ ```bash
19
+ uvx continuous-refactoring --help
20
+ ```
21
+
22
+ Or install it with [uv](https://docs.astral.sh/uv/guides/tools/):
23
+
9
24
  ```bash
10
25
  uv tool install continuous-refactoring
11
26
  ```
12
27
 
28
+ Or with [pipx](https://pypa.github.io/pipx/):
29
+
30
+ ```bash
31
+ pipx install continuous-refactoring
32
+ ```
33
+
34
+ Or with pip:
35
+
36
+ ```bash
37
+ pip install continuous-refactoring
38
+ ```
39
+
13
40
  For a checkout:
14
41
 
15
42
  ```bash
@@ -44,15 +71,18 @@ continuous-refactoring run \
44
71
  --max-attempts 2
45
72
  ```
46
73
 
47
- That keeps sweeping targets until it runs out, hits your caps, or starts failing.
74
+ That runs up to 10 refactor actions, then stops sooner if the finite target file
75
+ runs out or the loop starts failing. Use `run --focus-on-live-migrations` when
76
+ you want the loop to work only on eligible live migrations; it bypasses target
77
+ selection and `--max-refactors`.
48
78
 
49
79
  ## What it does
50
80
 
51
- - Resolves a target from `--targets`, `--globs`, `--extensions`, or `--paths`, with optional natural-language scoping via `--scope-instruction`.
81
+ - Resolves each source action from `--targets`, `--globs`, `--extensions`, or `--paths`, with optional natural-language scoping via `--scope-instruction`.
52
82
  - Runs the agent with a refactoring prompt + your "taste" guidelines.
53
83
  - Runs your validation command (default: `uv run pytest`).
54
84
  - If green and there's a diff, it commits locally and leaves the branch for you to inspect.
55
- - Repeats until it runs out of targets, hits the retry budget, or stacks too many failures.
85
+ - Repeats until it spends the action budget, exhausts a finite target file, hits the retry budget, or stacks too many failures.
56
86
 
57
87
  ## Requirements
58
88
 
@@ -66,6 +96,8 @@ That keeps sweeping targets until it runs out, hits your caps, or starts failing
66
96
  ```bash
67
97
  # 1. Register the repo (creates a project dir under ~/.local/share/continuous-refactoring)
68
98
  continuous-refactoring init
99
+ # Or keep project taste in the repo:
100
+ continuous-refactoring init --in-repo-taste
69
101
 
70
102
  # 2. (Optional) Write your refactoring taste — either edit the file, have an agent interview you,
71
103
  # or refine an existing draft collaboratively
@@ -90,13 +122,18 @@ continuous-refactoring run \
90
122
 
91
123
  | Command | What it does |
92
124
  |---|---|
93
- | `init` | Registers this directory as a project, creates a default `taste.md`, and can store `--live-migrations-dir`. |
125
+ | `init` | Registers this directory as a project, creates a default `taste.md`, and can store `--live-migrations-dir` or `--in-repo-taste`. |
94
126
  | `taste` | Prints the active taste file path. Add `--interview` to have an agent author it, `--refine` to iteratively improve an existing taste doc, `--upgrade` to refresh stale taste dimensions, `--global` for the shared file, and `--force` to let `--interview` overwrite custom content after writing a `.bak`. |
95
127
  | `run-once` | Single pass on one resolved target. No retry. If there is a diff and validation passes, it commits locally and prints the diffstat. |
96
- | `run` | The loop. Iterates targets, retries on failure, and commits successful targets locally. |
128
+ | `run` | The loop. Iterates refactor actions, retries on failure, and commits successful changes locally. Add `--focus-on-live-migrations` to bypass targeting and work only on eligible live migrations. |
97
129
  | `upgrade` | Checks that the global config manifest is current, rewrites it idempotently, and warns if the global taste file is stale. |
98
- | `review list` | Lists migrations flagged for human review (`awaiting_human_review`). |
99
- | `review perform <migration>` | Starts an interactive agent session to resolve a flagged migration's review. Requires `--with`, `--model`, and `--effort`. |
130
+ | `migration list` | Lists visible migrations. Add `--status <status>` or `--awaiting-review` to filter. |
131
+ | `migration doctor <slug-or-path>` | Validates one visible migration's consistency. |
132
+ | `migration doctor --all` | Validates every visible migration plus internal transaction state. |
133
+ | `migration review <slug-or-path>` | Starts staged review for a migration awaiting human review. Requires `--with`, `--model`, and `--effort`. |
134
+ | `migration refine <slug-or-path>` | Records feedback for a planning or unexecuted ready migration and runs one staged planning revision. Requires `--message <text>` or `--file <path>`, plus `--with`, `--model`, and `--effort`; add `--show-agent-logs` to mirror the planning agent. |
135
+
136
+ Legacy `review list` and `review perform <migration>` remain compatibility aliases; prefer `migration list --awaiting-review` and `migration review`.
100
137
 
101
138
  ## Targeting / Useful flags
102
139
 
@@ -107,21 +144,46 @@ Target resolution is first-match-wins:
107
144
 
108
145
  These flags are not mutually exclusive, but only the highest-priority populated source is used.
109
146
 
110
- - `--targets path/to/targets.jsonl` — explicit list; one JSON object per line with `description`, `files`, optional `scoping`, `model-override`, `effort-override`. Effort overrides use `low`, `medium`, `high`, or `xhigh`.
111
- - `--globs 'src/**/*.py:tests/**/*.py'` — colon-separated globs; each matched file becomes its own target.
112
- - `--extensions .py,.ts` — shorthand that expands to `**/*.py`, `**/*.ts`; each matched file becomes its own target.
113
- - `--paths a.py:b.py` — literal paths, all treated as one target.
114
- - `--scope-instruction "clean up the auth module"` — extra free-text scoping. If file-based targeting resolves nothing, this becomes the useful fallback context.
147
+ - `--targets path/to/targets.jsonl` — explicit finite list; one JSON object per line with `description`, `files`, optional `scoping`, `model-override`, `effort-override`. Effort overrides use `low`, `medium`, `high`, or `xhigh`. If `--max-refactors` is omitted, `run` processes the file once and stops.
148
+ - `--globs 'src/**/*.py:tests/**/*.py'` — colon-separated globs matched once against tracked files from `git ls-files`; each refactor action samples one matched file, so files can repeat.
149
+ - `--extensions .py,.ts` — shorthand that expands to `**/*.py`, `**/*.ts` against tracked files from `git ls-files`; each refactor action samples one matched file, so files can repeat.
150
+ - `--paths a.py:b.py` — literal user-provided paths, all treated as one grouped target; each refactor action reuses that group.
151
+ - `--scope-instruction "clean up the auth module"` — extra free-text scoping. If selected file patterns resolve nothing, this becomes the useful fallback context.
152
+
153
+ If `--globs` or `--extensions` match no tracked files and there is no
154
+ `--scope-instruction`, `run` completes successfully with zero refactor actions.
155
+ `--paths` is literal input and is not filtered through `git ls-files`.
115
156
 
116
- If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`, then `run` and `run-once` require `--scope-instruction`.
157
+ If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`,
158
+ then `run` and `run-once` require `--scope-instruction`; the driver still
159
+ random-samples tracked files from `git ls-files` for each action and uses the
160
+ scope text as context for that target.
117
161
 
118
162
  ### Migrations & taste flags
119
163
 
120
164
  - `init --live-migrations-dir PATH` — enables the larger-refactoring workflow for this project. The path is stored repo-relative in the project registry and created if missing.
165
+ - `init --in-repo-taste [PATH]` — stores this project's taste file in the repo and remembers the repo-relative path. Defaults to `.continuous-refactoring/taste.md`; re-run `init --in-repo-taste ...` to choose a different path.
166
+ - `migration list` — shows visible migrations; `--awaiting-review` narrows to human-review handoffs.
167
+ - `migration doctor <slug-or-path>` / `migration doctor --all` — read-only consistency checks. Doctor reports problems; it does not repair them.
168
+ - `migration review <slug-or-path> --with ... --model ... --effort ...` — resolves an `awaiting_human_review` migration through a staged workspace.
169
+ - `migration refine <slug-or-path> (--message <text>|--file <path>) --with ... --model ... --effort ... [--show-agent-logs]` — adds user feedback to a planning or unexecuted ready migration and resumes planning through the `revise` step when reopening ready work.
121
170
  - `taste --refine` — opens a collaborative editing session for the taste file. The agent keeps refining until you tell it to write, then the session ends automatically after the settled write.
122
171
  - `taste --upgrade` — re-interviews for taste dimensions added since your last version. No-op when already current; use `taste --refine` if you want to rework the doc anyway.
123
172
  - `taste --force` — only applies to `--interview`; it allows a customized taste file to be overwritten after backing it up to `taste.md.bak`.
124
173
 
174
+ Canonical migration commands:
175
+
176
+ ```bash
177
+ continuous-refactoring migration list
178
+ continuous-refactoring migration list --status planning
179
+ continuous-refactoring migration list --awaiting-review
180
+ continuous-refactoring migration doctor <slug-or-path>
181
+ continuous-refactoring migration doctor --all
182
+ continuous-refactoring migration review <slug-or-path> --with codex --model gpt-5 --effort high
183
+ continuous-refactoring migration refine <slug-or-path> --message "split the risky phase" --with codex --model gpt-5 --effort high
184
+ continuous-refactoring migration refine <slug-or-path> --file feedback.md --with codex --model gpt-5 --effort high
185
+ ```
186
+
125
187
  ### Shared `run` / `run-once` flags
126
188
 
127
189
  - `--with`, `--model` — required agent backend/model selection.
@@ -136,10 +198,11 @@ If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`, the
136
198
 
137
199
  ### `run`-only flags
138
200
 
139
- - `--max-attempts N` — per-target retry budget. `1` = no retry, `0` = unlimited (which means permanently broken targets will never give up).
140
- - `--max-refactors N` — cap the number of targets per run. Required unless you use `--targets`.
141
- - `--max-consecutive-failures N` — bail after N targets fail in a row. Default 3.
142
- - `--sleep SECONDS` — pause between completed targets. Useful when you want a long batch without hammering the repo or your agent budget.
201
+ - `--max-attempts N` — per-action retry budget. `1` = no retry, `0` = unlimited (which means permanently broken actions will never give up).
202
+ - `--max-refactors N` — cap the number of refactor actions per run. Required unless you use `--targets` or `--focus-on-live-migrations`.
203
+ - `--focus-on-live-migrations` — bypass target selection and `--max-refactors`; iterate eligible live migrations until they are done, deferred, blocked, or the failure budget trips.
204
+ - `--max-consecutive-failures N` — bail after N actions fail in a row. Default 3.
205
+ - `--sleep SECONDS` — pause between completed actions. Useful when you want a long batch without hammering the repo or your agent budget.
143
206
  - `--commit-message-prefix TEXT` — subject prefix for successful refactor or migration-plan commits. Default `continuous refactor`.
144
207
 
145
208
  ## Safety behaviors
@@ -156,22 +219,36 @@ If you provide none of `--targets`, `--globs`, `--extensions`, or `--paths`, the
156
219
  Each run writes to `$TMPDIR/continuous-refactoring/<run-id>/`:
157
220
 
158
221
  - `summary.json` — rolling status, counts, per-attempt stats
159
- - `events.jsonl` — structured event log
222
+ - `events.jsonl` — structured event log with call roles such as `classify`,
223
+ `planning.<step>`, `phase.ready-check`, `phase.execute`, and
224
+ `phase.validation`
160
225
  - `run.log` — human-readable log
161
226
  - `attempt-NNN/[retry-NN/]refactor/` — per-attempt agent + test stdout/stderr
227
+ - `baseline/initial/` — baseline validation stdout/stderr before work starts
228
+ - `classify/` — classifier agent stdout/stderr
229
+ - `scope-expansion/` — scope candidates, selection, and bypass reason
230
+ - `attempt-NNN/[retry-NN/]planning/<step>/` — planning agent stdout/stderr for
231
+ migration planning steps
232
+ - `phase-ready-check/` — phase precondition agent stdout/stderr
233
+ - `attempt-NNN/[retry-NN/]phase-execute/` — phase agent and validation logs
234
+ - `migration-probes/action-NNN/` — migration probe logs during normal `run`
235
+ actions, including planning, phase ready-checks, and phase execution
162
236
 
163
237
  Mixed-effort runs are auditable: summaries and call events record the default effort, max allowed effort, requested effort, effective effort, source, and whether the request was capped.
164
238
 
165
- The path prints at startup. Grep it when something goes sideways.
239
+ The path prints at startup. Grep it when something goes sideways. Failed
240
+ non-commit decisions also write durable XDG snapshots under the project failure
241
+ directory, usually
242
+ `~/.local/share/continuous-refactoring/projects/<uuid>/failures/`.
166
243
 
167
244
  ## Taste files
168
245
 
169
246
  The taste file is a short bullet list of your refactoring preferences. It gets injected into every agent prompt.
170
247
 
171
- - Project taste: `~/.local/share/continuous-refactoring/projects/<uuid>/taste.md`
248
+ - Project taste: `~/.local/share/continuous-refactoring/projects/<uuid>/taste.md`, or the repo-local path chosen with `init --in-repo-taste [PATH]`
172
249
  - Global taste: `~/.local/share/continuous-refactoring/global/taste.md`
173
250
 
174
- Project taste wins over global. Use `taste --interview` to bootstrap one, `taste --refine` to rework it with an agent, or edit the file directly any time.
251
+ Project taste wins over global. Use `taste` to print the active path, `taste --interview` to bootstrap one, `taste --refine` to rework it with an agent, or edit the file directly any time.
175
252
 
176
253
  ## Larger refactorings
177
254
 
@@ -190,7 +267,7 @@ This tells the CLI where to store migration artifacts. The path is repo-relative
190
267
  Each `run` / `run-once` tick now checks for eligible migration work before falling back to single-commit cleanups:
191
268
 
192
269
  1. **Classify** — a classifier agent reads the target and decides: `cohesive-cleanup` (one-shot path) or `needs-plan` (migration path).
193
- 2. **Plan** — for `needs-plan` targets, a six-stage planning workflow runs: generate approaches pick best expand into phases → review revise final review. Artifacts land under `<live-migrations-dir>/<migration-name>/`.
270
+ 2. **Plan** — for `needs-plan` targets, each automation action runs exactly one planning step: approaches, pick-best, expand, review, optional revise/review-2, then final-review. Accepted steps update `.planning/state.json`, store stdout under `.planning/stages/`, and publish through a staged transaction. Failed current-step output stays in run artifacts and is not resume input.
194
271
  3. **Execute** — each phase is a self-contained unit of work. The tick picks the oldest eligible migration, checks whether its current phase precondition is satisfied, and executes it on the current branch. Phase completion is judged against the phase file's `## Definition of Done`; commit message identifies the migration as `migration/<name>/<phase-file>.md`.
195
272
 
196
273
  ### Migration directory layout
@@ -199,14 +276,20 @@ Each `run` / `run-once` tick now checks for eligible migration work before falli
199
276
  <live-migrations-dir>/
200
277
  <migration-name>/
201
278
  manifest.json # status, phases, wake-up schedule
279
+ .planning/
280
+ state.json # durable planning cursor and accepted step refs
281
+ stages/ # accepted planning stdout, suffixed on repeats
202
282
  plan.md # the expanded plan
203
283
  approaches/ # candidate approaches considered during planning
204
284
  phase-1-<name>.md # per-phase specification
205
285
  phase-2-<name>.md
206
286
  ...
287
+ __transactions__/ # internal staged publish state
207
288
  __intentional_skips__/ # migrations rejected at final review
208
289
  ```
209
290
 
291
+ Do not edit `.planning/` or `__transactions__/` by hand. Use `migration doctor` when the shape looks wrong.
292
+
210
293
  ### Wake-up rules
211
294
 
212
295
  Migrations don't run on every tick. The scheduler now separates **activity** from
@@ -240,7 +323,7 @@ Before executing a phase, a ready-check agent verifies that the current phase pr
240
323
 
241
324
  - **ready: yes** — phase executes; on green tests, the phase is marked done, any prior deferral markers are cleared, and the migration advances immediately to the next phase.
242
325
  - **ready: no** — manifest activity is bumped, a retry cooldown is started, and a future `wake_up_on` is recorded when needed; the tick moves on.
243
- - **ready: unverifiable** — the migration is flagged `awaiting_human_review` and put on cooldown. Automated migration ticks skip flagged migrations until review clears the flag. Use `review list` to find it and `review perform <migration> --with ... --model ... --effort ...` to resolve it interactively.
326
+ - **ready: unverifiable** — the migration is flagged `awaiting_human_review` and put on cooldown. Automated migration ticks skip flagged migrations until review clears the flag. Use `migration list --awaiting-review` to find it and `migration review <slug-or-path> --with ... --model ... --effort ...` to resolve it interactively.
244
327
 
245
328
  Human-facing migration references use the relative phase spec path, for example `phase-2-failure-report.md`. The manifest cursor stores the phase `name`, not a numeric index.
246
329
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "continuous-refactoring"
3
- version = "0.1.0"
3
+ version = "0.3.0"
4
4
  description = "Continuous refactoring loop for AI coding agents"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"