From 0867bc8296517cbf41e184a3e0b9cb03b2efd041 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Thu, 4 Jun 2026 22:53:17 +0200 Subject: [PATCH] docs(refine): add Refine Task design spec Co-Authored-By: Claude Opus 4.7 --- .../specs/2026-06-04-refine-task-design.md | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-04-refine-task-design.md diff --git a/docs/superpowers/specs/2026-06-04-refine-task-design.md b/docs/superpowers/specs/2026-06-04-refine-task-design.md new file mode 100644 index 0000000..c078cb1 --- /dev/null +++ b/docs/superpowers/specs/2026-06-04-refine-task-design.md @@ -0,0 +1,127 @@ +# Refine Task — Design + +**Date:** 2026-06-04 +**Status:** Approved (pending spec review) + +## Goal + +Add a one-click **Refine Task** action to a task card. Clicking it spawns a +headless Claude session that reads the task (and the repo), rewrites the task's +description to be clearer and runnable autonomously, and — where it helps — +breaks the work into subtasks. The user then reviews/hand-edits the result and +queues the task manually. + +This is **not** an interactive terminal session. It is a fire-and-forget +headless run, structurally similar to the existing daily-prep ("Prime Claude") +flow (`PrimeRunner`), not the interactive planning flow. + +## Non-goals / scope + +- No new task status. The task stays `Idle` throughout; refine only mutates the + task's `Title`/`Description` and its subtasks. +- No worktree, no interactive terminal, no auto-queue. +- No per-task refine config (model, turns) — uses the worker's defaults. +- Refine does not edit repository files; repo access is read-only. + +## User flow + +1. User clicks the refine icon on an `Idle` task's card. +2. UI calls `WorkerHub.RefineTask(taskId)` → `RefineRunner`. +3. `RefineRunner` spawns `claude -p` headless in the list's working directory, + seeded with a fixed refine prompt + the task's title/description/current + subtasks + the task id. +4. Claude reads the repo (read-only), then calls: + - `mcp__claudedo__update_task` to improve title/description, and + - `mcp__claudedo__add_subtask` to add steps where useful. + Each MCP call broadcasts `TaskUpdated`, so the description and Steps card + update live in the UI. +5. Run finishes; the card's refine button returns to its idle state. User + reviews, optionally hand-edits the description/steps, then queues manually. + +## Architecture + +### Worker — `RefineRunner` + +- New `Worker/Refine/RefineRunner.cs` implementing `IRefineRunner` + (`Worker/Refine/Interfaces/IRefineRunner.cs`). Modeled on `PrimeRunner`. +- **Concurrency / single-flight:** an in-flight `HashSet` of task ids + guarded by a lock (or `SemaphoreSlim`), so the *same* task cannot refine + twice concurrently, but different tasks may refine in parallel. A second + click on an already-refining task is a no-op. +- **Guards:** only runs when `task.Status == Idle`. Resolves the list's working + directory. If the list has **no valid working dir**, fall back to a sandbox + directory and run text-only (drop `Read`/`Grep`/`Glob` from the allowlist). +- **CLI invocation** (relies on the globally-registered `claudedo` MCP, like + daily-prep — no `--mcp-config`): + ``` + claude -p --output-format stream-json --verbose + --permission-mode acceptEdits + --max-turns + --allowedTools mcp__claudedo__get_task,mcp__claudedo__update_task,mcp__claudedo__add_subtask,Read,Grep,Glob + ``` + `Edit`/`Write`/`Bash` are deliberately **not** whitelisted, so the run is + read-only on the repo even under `acceptEdits`. (Chosen over `plan` mode to + avoid the headless "exit plan mode to act" friction; the allowlist is the + real read-only gate.) +- **Logging:** stream stdout to a per-run log at + `logs/refine-.log`, truncated at the start of each run. + +### Prompt — `PromptKind.Refine` + +- Add `Refine` to the `PromptKind` enum in `PromptFiles.cs`, file + `prompts/refine.md`, with a bundled default. +- Default prompt instructs: refine one ClaudeDo task so it is ready to run + autonomously; ground the description in the actual code (read-only); keep + scope tight (no scope creep into adjacent work); add steps as subtasks only + when they genuinely help; use only `get_task`, `update_task`, `add_subtask` + and the read-only tools; never edit files. +- Rendered via `PromptFiles.Render` with `{taskId}`, `{title}`, + `{description}`, and the current subtask list seeded into the prompt so the + agent knows which steps already exist. + +### MCP tool — `add_subtask` + +- New `[McpServerTool]` on `ExternalMcpService` (part of the global `claudedo` + MCP), signature `add_subtask(taskId, title, orderNum?)`. +- Creates a `SubtaskEntity` via `SubtaskRepository`; `orderNum` defaults to + append-at-end (max existing + 1). Refuses if the task is `Running`. + Broadcasts `TaskUpdated`. +- **Append semantics, not replace:** the current subtasks are already in the + prompt, so the agent only adds missing steps; re-running refine will not + silently wipe steps the user hand-edited. +- `update_task` already exists (title/description/commitType) and is reused + unchanged. + +### UI — button, icon, feedback + +- **Icon:** add the supplied SVG as an `Icon.Refine` `StreamGeometry` in + `IslandStyles.axaml`, rendered as a **stroked `Path`** (`plan-icon` style, + fill none) — it is line art, so per the PathIcon-fills-geometry gotcha it + must be stroked, not filled. +- **Button:** a new `icon-btn` in `TaskRowView.axaml` near the star button, + visible only when the task is `Idle`. Bound to a new `RefineTaskCommand` on + `TasksIslandViewModel`. +- **Feedback:** new broadcaster events `RefineStarted(taskId)` / + `RefineFinished(taskId, ok, error?)` drive an `IsRefining` flag on + `TaskRowViewModel`; the button shows a busy/disabled state while running. The + description and Steps card update live via the existing `TaskUpdated` events + fired by the MCP calls. +- Wire `RefineTask` through `IWorkerClient` / `WorkerClient`, the `WorkerHub` + method, and update the hand-rolled test fakes in both test projects. + +## Testing + +- `add_subtask`: creates the row, appends order correctly, refuses when + `Running`, broadcasts `TaskUpdated`. +- Refine prompt builder and CLI-args builder produce the expected prompt/flags + (including the text-only fallback when no working dir). +- `RefineRunner` guards: `Idle`-only, per-task single-flight no-op on a second + concurrent call. +- **No test spawns the real `claude` CLI** (project rule). The end-to-end run + is a manual smoke step. + +## Open implementation calls (decided) + +- **Permission mode:** `acceptEdits` + restricted allowlist for read-only + (rather than `plan` mode). +- **`add_subtask`:** append-only (rather than replace-all).