lemming-cli 0.2.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 (133) hide show
  1. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/PKG-INFO +29 -12
  2. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/README.md +28 -11
  3. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/docs/HOOKS.md +19 -4
  4. lemming_cli-0.3.0/docs/screenshots/dashboard-desktop.png +0 -0
  5. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/docs/screenshots/dashboard-mobile.png +0 -0
  6. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/package-lock.json +4 -4
  7. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/package.json +1 -1
  8. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/pyproject.toml +1 -1
  9. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/hooks_test.py +3 -0
  10. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/tasks.py +35 -1
  11. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/tasks_test.py +34 -1
  12. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/tasks.py +231 -67
  13. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/tasks_test.py +139 -6
  14. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/readability.py +134 -2
  15. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/readability_test.py +80 -1
  16. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/roadmap.py +162 -0
  17. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/roadmap_test.py +63 -5
  18. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/trial_test.py +2 -1
  19. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/hooks_test.py +5 -0
  20. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/models.py +4 -0
  21. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/models_test.py +4 -0
  22. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/orchestrator.py +17 -4
  23. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/orchestrator_test.py +38 -0
  24. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/persistence_test.py +23 -0
  25. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/prompts/hooks/50-readability.md +20 -7
  26. lemming_cli-0.3.0/src/lemming/prompts/hooks/70-ux.md +55 -0
  27. lemming_cli-0.3.0/src/lemming/prompts/hooks/90-roadmap.md +79 -0
  28. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/prompts.py +3 -0
  29. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/prompts_test.py +35 -0
  30. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/runner.py +36 -4
  31. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/runner_test.py +53 -0
  32. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/__init__.py +9 -0
  33. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/lifecycle.py +38 -0
  34. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/lifecycle_test.py +24 -0
  35. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/operations.py +76 -4
  36. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/operations_test.py +69 -3
  37. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/queries.py +45 -1
  38. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/queries_test.py +22 -0
  39. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/dashboard.spec.js +62 -0
  40. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/dashboard.test.js +289 -19
  41. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/files.html +4 -1
  42. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/index.html +106 -22
  43. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/index.js +139 -24
  44. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/logs.html +15 -0
  45. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/logs.test.js +29 -0
  46. lemming_cli-0.3.0/src/lemming/web/mancha.js +58 -0
  47. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/screenshots.spec.js +0 -1
  48. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/uv.lock +1 -1
  49. lemming_cli-0.2.0/docs/screenshots/dashboard-desktop.png +0 -0
  50. lemming_cli-0.2.0/src/lemming/prompts/hooks/90-roadmap.md +0 -61
  51. lemming_cli-0.2.0/src/lemming/web/mancha.js +0 -58
  52. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/.github/workflows/ci.yml +0 -0
  53. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/.github/workflows/publish.yml +0 -0
  54. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/.github/workflows/screenshots.yml +0 -0
  55. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/.gitignore +0 -0
  56. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/.prettierignore +0 -0
  57. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/.prettierrc +0 -0
  58. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/Dockerfile +0 -0
  59. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/LICENSE +0 -0
  60. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/biome.json +0 -0
  61. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/docker-compose.yml +0 -0
  62. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/docs/EVALS.md +0 -0
  63. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/docs/screenshots/task-log-desktop.png +0 -0
  64. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/docs/screenshots/task-log-mobile.png +0 -0
  65. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/playwright.config.js +0 -0
  66. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/__init__.py +0 -0
  67. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/__init__.py +0 -0
  68. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/auth.py +0 -0
  69. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/auth_test.py +0 -0
  70. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/config.py +0 -0
  71. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/config_test.py +0 -0
  72. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/conftest.py +0 -0
  73. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/context.py +0 -0
  74. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/context_test.py +0 -0
  75. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/directories.py +0 -0
  76. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/directories_test.py +0 -0
  77. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/files.py +0 -0
  78. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/files_test.py +0 -0
  79. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/hooks.py +0 -0
  80. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/logging.py +0 -0
  81. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/logging_test.py +0 -0
  82. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/loop.py +0 -0
  83. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/loop_test.py +0 -0
  84. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/main.py +0 -0
  85. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api/main_test.py +0 -0
  86. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/api_test.py +0 -0
  87. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/__init__.py +0 -0
  88. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/config.py +0 -0
  89. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/config_test.py +0 -0
  90. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/goal.py +0 -0
  91. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/goal_test.py +0 -0
  92. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/hooks.py +0 -0
  93. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/hooks_test.py +0 -0
  94. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/main.py +0 -0
  95. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/main_test.py +0 -0
  96. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/operations.py +0 -0
  97. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/operations_test.py +0 -0
  98. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/progress.py +0 -0
  99. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/progress_test.py +0 -0
  100. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/readability_cli.py +0 -0
  101. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli/readability_cli_test.py +0 -0
  102. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/cli_test.py +0 -0
  103. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/conftest.py +0 -0
  104. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/__init__.py +0 -0
  105. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/__main__.py +0 -0
  106. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/cli.py +0 -0
  107. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/cli_test.py +0 -0
  108. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/container.py +0 -0
  109. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/container_test.py +0 -0
  110. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/fixtures.py +0 -0
  111. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/fixtures_test.py +0 -0
  112. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/harness.py +0 -0
  113. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/harness_test.py +0 -0
  114. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/scenarios.py +0 -0
  115. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/scenarios_test.py +0 -0
  116. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/suites.py +0 -0
  117. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/evals/trial.py +0 -0
  118. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/hooks.py +0 -0
  119. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/integration_test.py +0 -0
  120. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/main.py +0 -0
  121. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/main_test.py +0 -0
  122. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/paths.py +0 -0
  123. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/paths_test.py +0 -0
  124. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/persistence.py +0 -0
  125. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/prompts/hooks/60-testing.md +0 -0
  126. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/prompts/taskrunner.md +0 -0
  127. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/providers.py +0 -0
  128. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/providers_test.py +0 -0
  129. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/progress.py +0 -0
  130. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/tasks/progress_test.py +0 -0
  131. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/favicon.js +0 -0
  132. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/favicon.spec.js +0 -0
  133. {lemming_cli-0.2.0 → lemming_cli-0.3.0}/src/lemming/web/files.spec.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lemming-cli
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: An autonomous, iterative task runner for AI coding agents.
5
5
  Project-URL: Homepage, https://github.com/owahltinez/lemming
6
6
  Project-URL: Repository, https://github.com/owahltinez/lemming
@@ -186,11 +186,17 @@ Lemming comes with several built-in hooks to help manage your project:
186
186
  analyzes the results of the finished task and decides if the remaining roadmap
187
187
  needs to be adjusted (e.g., adding a missing prerequisite, skipping obsolete
188
188
  tasks, or breaking down a broad task).
189
- - **`readability`**: A code quality hook that reviews changes for adherence to
190
- the Google Style Guide and general readability using the
189
+ - **`readability`**: A code quality and simplification hook that challenges
190
+ unnecessary complexity and duplicate implementations, then reviews changes
191
+ for adherence to the Google Style Guide and general readability using the
191
192
  [readability](https://github.com/owahltinez/readability) tool (exposed as
192
193
  `lemming readability`). It can record findings as task progress or suggest
193
194
  follow-up refactoring tasks.
195
+ - **`testing`**: Verifies that changed behavior has focused test coverage and
196
+ that the relevant tests pass.
197
+ - **`ux`**: Reviews at most one critical user journey affected by a
198
+ user-visible change. It reports only concrete, reproducible continuity gaps
199
+ and exits immediately for non-user-facing tasks.
194
200
 
195
201
  ### Custom and Global Hooks
196
202
 
@@ -240,13 +246,20 @@ See [docs/EVALS.md](docs/EVALS.md) for details.
240
246
 
241
247
  ### Roadmap Management
242
248
 
243
- - **`status [<id>]`**: Roadmap overview or deep-dive into a specific task.
249
+ - **`status [<id>]`**: Queue/history overview or deep-dive into a specific
250
+ task, including supersession lineage and runner/orchestrator-hook execution
251
+ times. Superseded and failed history stays visible in the default overview;
252
+ `--verbose` also shows routine completed/cancelled history.
244
253
  - **`goal [<text>]`**: Set or view the long-term goal shared by all tasks.
245
254
  Supports `-f/--file`.
246
255
  - **`add <desc>`**: Append a new task. Supports `--index` and `--runner`.
247
256
  - **`edit <id>`**: Modify a task's description, runner, or position.
248
- - **`delete <id>`**: Remove a task. Supports `--all` and `--completed` for bulk
249
- operations.
257
+ - **`delete <id>`**: Remove an unstarted task while retaining its runner log.
258
+ Tasks with execution history require `--force`; autonomous restructuring
259
+ should use `supersede`. Supports `--all` and `--completed` for bulk cleanup,
260
+ including logs.
261
+ - **`supersede <id> --reason <text>`**: Retire a replaced or split task without
262
+ losing its progress, timings, log, or links to replacement tasks.
250
263
  - **`progress`**: Manage progress entries and findings for specific tasks.
251
264
  - `list <id>`: List all progress for a task.
252
265
  - `add <id> <finding>`: Record a new technical detail.
@@ -277,9 +290,11 @@ See [docs/EVALS.md](docs/EVALS.md) for details.
277
290
  - **`fail <id>`**: Mark a task as a terminal failure (will not be retried).
278
291
  - **`cancel <id>`**: Stop an in-progress task (kills the runner process).
279
292
  - **`reset <id>`**: Clear attempts and progress to start a task fresh.
280
- - **`logs [<id>]`**: Print a task's execution log to stdout. If no ID is
281
- provided, it defaults to the active or most recent task. Orchestrator hook
282
- output is automatically appended.
293
+ - Superseded tasks remain visible as non-failing history; replacement tasks
294
+ link back through their parent task ID.
295
+ - **`logs [<id>]`**: Print a task's execution log to stdout, including retained
296
+ logs for removed tasks. If no ID is provided, it defaults to the active or
297
+ most recent task. Orchestrator hook output is automatically appended.
283
298
 
284
299
  ### Execution
285
300
 
@@ -307,10 +322,12 @@ Lemming uses **fuzzy matching** to automatically inject the correct "YOLO"
307
322
  - **Antigravity (`agy`)**: Adds `--dangerously-skip-permissions`
308
323
  - **Aider**: Adds `--yes --quiet`
309
324
  - **Claude**: Adds `--dangerously-skip-permissions`
310
- - **Codex**: Adds `--yolo`
325
+ - **Codex**: Runs non-interactively via `codex exec`, adds `--json`, and, in
326
+ YOLO mode, adds `--dangerously-bypass-approvals-and-sandbox`
311
327
 
312
- You can disable this behavior with `--no-defaults`, or use a **template** to
313
- fully control the command layout:
328
+ You can disable default flag injection with `--no-defaults` (`codex exec`
329
+ remains the Codex execution interface), or use a **template** to fully control
330
+ the command layout:
314
331
 
315
332
  ```bash
316
333
  lemming run --runner "my-tool --input={{prompt}} --json"
@@ -164,11 +164,17 @@ Lemming comes with several built-in hooks to help manage your project:
164
164
  analyzes the results of the finished task and decides if the remaining roadmap
165
165
  needs to be adjusted (e.g., adding a missing prerequisite, skipping obsolete
166
166
  tasks, or breaking down a broad task).
167
- - **`readability`**: A code quality hook that reviews changes for adherence to
168
- the Google Style Guide and general readability using the
167
+ - **`readability`**: A code quality and simplification hook that challenges
168
+ unnecessary complexity and duplicate implementations, then reviews changes
169
+ for adherence to the Google Style Guide and general readability using the
169
170
  [readability](https://github.com/owahltinez/readability) tool (exposed as
170
171
  `lemming readability`). It can record findings as task progress or suggest
171
172
  follow-up refactoring tasks.
173
+ - **`testing`**: Verifies that changed behavior has focused test coverage and
174
+ that the relevant tests pass.
175
+ - **`ux`**: Reviews at most one critical user journey affected by a
176
+ user-visible change. It reports only concrete, reproducible continuity gaps
177
+ and exits immediately for non-user-facing tasks.
172
178
 
173
179
  ### Custom and Global Hooks
174
180
 
@@ -218,13 +224,20 @@ See [docs/EVALS.md](docs/EVALS.md) for details.
218
224
 
219
225
  ### Roadmap Management
220
226
 
221
- - **`status [<id>]`**: Roadmap overview or deep-dive into a specific task.
227
+ - **`status [<id>]`**: Queue/history overview or deep-dive into a specific
228
+ task, including supersession lineage and runner/orchestrator-hook execution
229
+ times. Superseded and failed history stays visible in the default overview;
230
+ `--verbose` also shows routine completed/cancelled history.
222
231
  - **`goal [<text>]`**: Set or view the long-term goal shared by all tasks.
223
232
  Supports `-f/--file`.
224
233
  - **`add <desc>`**: Append a new task. Supports `--index` and `--runner`.
225
234
  - **`edit <id>`**: Modify a task's description, runner, or position.
226
- - **`delete <id>`**: Remove a task. Supports `--all` and `--completed` for bulk
227
- operations.
235
+ - **`delete <id>`**: Remove an unstarted task while retaining its runner log.
236
+ Tasks with execution history require `--force`; autonomous restructuring
237
+ should use `supersede`. Supports `--all` and `--completed` for bulk cleanup,
238
+ including logs.
239
+ - **`supersede <id> --reason <text>`**: Retire a replaced or split task without
240
+ losing its progress, timings, log, or links to replacement tasks.
228
241
  - **`progress`**: Manage progress entries and findings for specific tasks.
229
242
  - `list <id>`: List all progress for a task.
230
243
  - `add <id> <finding>`: Record a new technical detail.
@@ -255,9 +268,11 @@ See [docs/EVALS.md](docs/EVALS.md) for details.
255
268
  - **`fail <id>`**: Mark a task as a terminal failure (will not be retried).
256
269
  - **`cancel <id>`**: Stop an in-progress task (kills the runner process).
257
270
  - **`reset <id>`**: Clear attempts and progress to start a task fresh.
258
- - **`logs [<id>]`**: Print a task's execution log to stdout. If no ID is
259
- provided, it defaults to the active or most recent task. Orchestrator hook
260
- output is automatically appended.
271
+ - Superseded tasks remain visible as non-failing history; replacement tasks
272
+ link back through their parent task ID.
273
+ - **`logs [<id>]`**: Print a task's execution log to stdout, including retained
274
+ logs for removed tasks. If no ID is provided, it defaults to the active or
275
+ most recent task. Orchestrator hook output is automatically appended.
261
276
 
262
277
  ### Execution
263
278
 
@@ -285,10 +300,12 @@ Lemming uses **fuzzy matching** to automatically inject the correct "YOLO"
285
300
  - **Antigravity (`agy`)**: Adds `--dangerously-skip-permissions`
286
301
  - **Aider**: Adds `--yes --quiet`
287
302
  - **Claude**: Adds `--dangerously-skip-permissions`
288
- - **Codex**: Adds `--yolo`
303
+ - **Codex**: Runs non-interactively via `codex exec`, adds `--json`, and, in
304
+ YOLO mode, adds `--dangerously-bypass-approvals-and-sandbox`
289
305
 
290
- You can disable this behavior with `--no-defaults`, or use a **template** to
291
- fully control the command layout:
306
+ You can disable default flag injection with `--no-defaults` (`codex exec`
307
+ remains the Codex execution interface), or use a **template** to fully control
308
+ the command layout:
292
309
 
293
310
  ```bash
294
311
  lemming run --runner "my-tool --input={{prompt}} --json"
@@ -51,15 +51,30 @@ a broad task).
51
51
 
52
52
  ### `readability`
53
53
 
54
- A code quality hook that reviews changes for adherence to the Google Style Guide
55
- and general readability using the bundled `lemming readability` tool. It
56
- provides feedback via task progress or suggests follow-up refactoring tasks.
54
+ A code quality and simplification hook that challenges unnecessary complexity,
55
+ indirection, and duplicated implementations before reviewing changes for
56
+ adherence to the Google Style Guide and general readability using the bundled
57
+ `lemming readability` tool. It provides feedback via task progress or suggests
58
+ follow-up refactoring tasks.
59
+
60
+ ### `testing`
61
+
62
+ Checks that changed behavior has focused test coverage and runs the relevant
63
+ tests. It records larger testing gaps as task progress for the roadmap hook.
64
+
65
+ ### `ux`
66
+
67
+ A lightweight journey-continuity review for user-visible changes. It considers
68
+ at most one affected critical journey, reports only concrete and reproducible
69
+ gaps, and exits immediately when the task did not change user-facing behavior.
70
+ It runs after `testing` and before `roadmap`.
57
71
 
58
72
  ### Editing Built-in Hook Prompts
59
73
 
60
74
  The built-in hook prompts are load-bearing: a wording change can regress
61
75
  orchestration behavior without any unit test failing. When you edit a prompt
62
- under `src/lemming/prompts/hooks/`, run its eval suite before shipping:
76
+ under `src/lemming/prompts/hooks/` that has an eval suite, run it before
77
+ shipping:
63
78
 
64
79
  ```bash
65
80
  uv run python -m lemming.evals run --suite roadmap
@@ -12,7 +12,7 @@
12
12
  "@biomejs/biome": "1.9.4",
13
13
  "@playwright/test": "^1.60.0",
14
14
  "jsdom": "latest",
15
- "mancha": "^0.22.4",
15
+ "mancha": "^0.22.7",
16
16
  "playwright": "^1.60.0"
17
17
  }
18
18
  },
@@ -1019,9 +1019,9 @@
1019
1019
  }
1020
1020
  },
1021
1021
  "node_modules/mancha": {
1022
- "version": "0.22.4",
1023
- "resolved": "https://registry.npmjs.org/mancha/-/mancha-0.22.4.tgz",
1024
- "integrity": "sha512-bNurE3cVS3ZoOow3hhkJiJcxRkXCZrWh4NaVVlV1KYFe3iY3wrcAqk/HJKMHw0kglcQjUc2iAtJbemI2oJKIUg==",
1022
+ "version": "0.22.7",
1023
+ "resolved": "https://registry.npmjs.org/mancha/-/mancha-0.22.7.tgz",
1024
+ "integrity": "sha512-ZClxBTYOKSD9f4KqW8lCMYVEUPhxzIRgihw5g20QrD4kzZ9JcQ383LXXkPMVTaCAjLlqYaF3brUMYACwWgQZgA==",
1025
1025
  "dev": true,
1026
1026
  "license": "MIT",
1027
1027
  "dependencies": {
@@ -16,7 +16,7 @@
16
16
  "@biomejs/biome": "1.9.4",
17
17
  "@playwright/test": "^1.60.0",
18
18
  "jsdom": "latest",
19
- "mancha": "^0.22.4",
19
+ "mancha": "^0.22.7",
20
20
  "playwright": "^1.60.0"
21
21
  }
22
22
  }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "lemming-cli"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "An autonomous, iterative task runner for AI coding agents."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -15,6 +15,9 @@ def test_list_hooks(client, test_tasks, monkeypatch, tmp_path):
15
15
  assert hooks["roadmap"]["masked"] is False
16
16
  assert hooks["readability"]["source"] == "built-in"
17
17
  assert hooks["readability"]["runs_on_failure"] is False
18
+ assert hooks["ux"]["priority"] == 70
19
+ assert hooks["ux"]["source"] == "built-in"
20
+ assert hooks["ux"]["runs_on_failure"] is False
18
21
 
19
22
  # Hooks are sorted by ascending priority
20
23
  priorities = [h["priority"] for h in payload]
@@ -76,6 +76,11 @@ def update_task(
76
76
  """Update a task's description, runner, position, status, or parent."""
77
77
  tasks_file = context.resolve_tasks_file(request.app.state, project)
78
78
  status = update.get("status")
79
+ if status == tasks.TaskStatus.SUPERSEDED:
80
+ raise fastapi.HTTPException(
81
+ 400,
82
+ "Use the supersede endpoint so a reason is recorded.",
83
+ )
79
84
 
80
85
  # Validation: require progress if completing or failing from the UI,
81
86
  # but not if we are just marking a finished task as pending (uncomplete).
@@ -91,6 +96,7 @@ def update_task(
91
96
  tasks.TaskStatus.COMPLETED,
92
97
  tasks.TaskStatus.FAILED,
93
98
  tasks.TaskStatus.CANCELLED,
99
+ tasks.TaskStatus.SUPERSEDED,
94
100
  ):
95
101
  require_progress = True
96
102
 
@@ -130,11 +136,39 @@ def delete_task(
130
136
  ):
131
137
  """Delete a single task by ID."""
132
138
  tasks.delete_tasks(
133
- context.resolve_tasks_file(request.app.state, project), task_id=task_id
139
+ context.resolve_tasks_file(request.app.state, project),
140
+ task_id=task_id,
141
+ force=True,
134
142
  )
135
143
  return {"status": "ok"}
136
144
 
137
145
 
146
+ class SupersedeTaskRequest(pydantic.BaseModel):
147
+ """Request body for superseding a task."""
148
+
149
+ reason: str
150
+
151
+
152
+ @router.post("/api/tasks/{task_id}/supersede")
153
+ def supersede_task(
154
+ request: fastapi.Request,
155
+ task_id: str,
156
+ body: SupersedeTaskRequest,
157
+ project: str | None = None,
158
+ ):
159
+ """Supersede a task while retaining its history."""
160
+ try:
161
+ return tasks.supersede_task(
162
+ context.resolve_tasks_file(request.app.state, project),
163
+ task_id,
164
+ body.reason,
165
+ )
166
+ except ValueError as e:
167
+ if "not found" in str(e):
168
+ raise fastapi.HTTPException(404, str(e))
169
+ raise fastapi.HTTPException(400, str(e))
170
+
171
+
138
172
  @router.post("/api/tasks/{task_id}/cancel")
139
173
  def cancel_task_endpoint(
140
174
  request: fastapi.Request, task_id: str, project: str | None = None
@@ -174,6 +174,25 @@ def test_reopen_cancelled_task_via_api(client, test_tasks):
174
174
  assert response.json()["attempts"] == 0
175
175
 
176
176
 
177
+ def test_supersede_and_reopen_task_via_api(client, test_tasks):
178
+ response = client.post(
179
+ "/api/tasks/task2/supersede",
180
+ json={"reason": "split after timeout"},
181
+ )
182
+ assert response.status_code == 200
183
+ assert response.json()["status"] == tasks.TaskStatus.SUPERSEDED
184
+ assert response.json()["superseded_reason"] == "split after timeout"
185
+
186
+ response = client.post(
187
+ "/api/tasks/task2/update",
188
+ json={"status": tasks.TaskStatus.PENDING},
189
+ )
190
+ assert response.status_code == 200
191
+ assert response.json()["status"] == tasks.TaskStatus.PENDING
192
+ assert response.json()["superseded_reason"] is None
193
+ assert response.json()["superseded_at"] is None
194
+
195
+
177
196
  def test_has_log_population(client, test_tasks):
178
197
  # Initially no logs
179
198
  response = client.get("/api/data")
@@ -225,7 +244,7 @@ def test_api_log(client, test_tasks):
225
244
  assert response.json() == {"log": ""}
226
245
 
227
246
 
228
- def test_api_delete_log_cleanup(client, test_tasks):
247
+ def test_api_delete_retains_log(client, test_tasks):
229
248
  test_tasks_file = test_tasks
230
249
  # 1. Add a task
231
250
  data = tasks.load_tasks(test_tasks_file)
@@ -248,6 +267,20 @@ def test_api_delete_log_cleanup(client, test_tasks):
248
267
 
249
268
  # 3. Delete via API
250
269
  response = client.post(f"/api/tasks/{task_id}/delete")
270
+ assert response.status_code == 200
271
+ assert log_file.read_text() == "API delete log"
272
+
273
+ response = client.get(f"/api/tasks/{task_id}/log")
274
+ assert response.status_code == 200
275
+ assert response.json() == {"log": "API delete log"}
276
+
277
+
278
+ def test_api_delete_completed_cleans_up_log(client, test_tasks):
279
+ log_file = paths.get_log_file(test_tasks, "task1")
280
+ log_file.write_text("completed task log")
281
+
282
+ response = client.post("/api/tasks/delete-completed")
283
+
251
284
  assert response.status_code == 200
252
285
  assert not log_file.exists()
253
286