--- name: hk-refine description: "Iteratively improve any output by running a structured observe-hypothesize-change-rerun loop. Uses an organized scratch directory to prevent context blowup — the conversation stays thin while iterations accumulate on disk. Use when an output (reflection, plan, prompt, pipeline result) isn't good enough and needs systematic refinement. Triggers on: 'close the loop', 'this output isn't good enough', 'iterate on this', 'refine this output', 'improve this reflection', or /hk-refine." argument-hint: "[scratch_dir] [description of what to improve]" allowed-tools: Bash, Read, Edit, Write, Task, Grep, Glob --- # /hk-refine — Iterative Output Refinement You have an open loop: something produced output, the output isn't good enough, and you need to systematically improve it. This skill closes that loop. The core discipline: **everything lives on disk, not in conversation context.** The scratch directory is the organized record of what was tried, what worked, and why. Subagents read from disk, write to disk, and report back in 2-3 line summaries. The main conversation only holds the current hypothesis and verdict — never full outputs. ## Context $ARGUMENTS If the context above is empty or unclear, ask the user: 1. What produced the output? (command, prompt, pipeline step) 2. What's wrong with it? (vague is ok — "it's not good enough" is a valid start) 3. Where should the scratch directory live? (suggest `temp_reflections/` or `temp_loop/`) ## The Scratch Directory This is the product. Not temp files — the organized log of the refinement process. ``` / ├── loop.md # Live loop state (see template below) ├── baseline/ │ ├── output.md # Original output that needs improvement │ ├── critique.md # Structured critique of what's wrong │ └── run_command.txt # Exact command/process that produced the output ├── iter-1/ │ ├── hypothesis.md # What to change and why │ ├── changes.md # What was actually changed (with file paths and diffs) │ ├── output.md # New output after changes │ ├── comparison.md # Before vs after, structured │ └── verdict.md # Better / worse / mixed — with evidence ├── iter-2/ │ └── ... └── summary.md # Written when loop closes ``` ### loop.md template This file is the single source of truth for where the loop is. Read it at the start of every iteration. Update it after every verdict. ```markdown # Close-the-Loop: [short description] ## Target What we're improving: [one line] Run command: [the exact command to re-run] Quality signal: [how we know it's better — specific, measurable if possible] ## Current State Iteration: [N] Best so far: [baseline | iter-N] Status: [observing | hypothesizing | changing | running | comparing | closed] ## Hypothesis Log - iter-1: [hypothesis] → [verdict: better/worse/mixed] - iter-2: [hypothesis] → [verdict] - ... ## What We've Learned - [Accumulated insights that carry forward — things that definitely help or definitely don't] ## Next [What to try next, or "CLOSED: [reason]"] ``` ## The Loop ### Phase 0: SET UP (first invocation only) 1. Create the scratch directory structure 2. Capture the baseline output — either from the user's clipboard/description, or by running the command 3. Write `run_command.txt` with the exact command that produces the output 4. Write `loop.md` with initial state 5. Proceed to Phase 1 ### Phase 1: OBSERVE Delegate critique to a subagent (sonnet). The subagent reads the current output and produces a structured critique. The main conversation does NOT read the full output — only the critique summary. ``` Task(model: sonnet, subagent_type: general-purpose) Read /[baseline or iter-N]/output.md Produce a structured critique: 1. STRENGTHS: What's working well (keep these) 2. WEAKNESSES: What's not working, ranked by impact 3. MISSING: What should be there but isn't 4. EXCESS: What's there but shouldn't be (noise, fluff, wrong focus) 5. ROOT ISSUE: The single biggest thing to fix (not a list — pick one) Write your critique to /[baseline or iter-N]/critique.md Return a 3-line summary: the root issue, the top weakness, and one strength to preserve. ``` ### Phase 2: HYPOTHESIZE Based on the critique summary (not the full output), form a hypothesis. This happens in the main conversation — it's a judgment call, not mechanical work. Write to `/iter-N/hypothesis.md`: ```markdown # Hypothesis for Iteration N ## What to change [Specific change — which file, which prompt section, which config value] ## Why this should help [Connect the change to the root issue from the critique] ## What to watch for [Side effects — things that might get worse when this gets better] ## Estimated impact [High / Medium / Low — on the specific quality signal defined in loop.md] ``` The hypothesis must be specific enough that someone else could apply the change without seeing the conversation. "Make the prompt better" is not a hypothesis. "Add a structured output format requirement to the reflection prompt because the current output is unstructured prose that's hard to evaluate" is a hypothesis. ### Phase 3: CHANGE Apply the changes described in the hypothesis. This could be: - Editing a prompt file - Changing a config value - Modifying code that processes/generates the output - Adjusting parameters (model, temperature, max tokens) Log what changed in `/iter-N/changes.md`: ```markdown # Changes for Iteration N ## Files modified - `path/to/file.py` — [what changed, 1 line] - `path/to/prompt.md` — [what changed, 1 line] ## Diffs [Actual diffs or before/after snippets for each change] ``` ### Phase 4: RUN Execute the command from `run_command.txt` to produce new output. Capture the output to `/iter-N/output.md`. If the run command involves `odin exec`, `odin reflect`, or similar commands that can't run inside Claude Code, provide the user with copy-paste commands and wait for them to paste the output back. Note this in loop.md's status. If the run command is something that CAN run (a Python script, a test, an API call), run it directly. ### Phase 5: COMPARE Delegate comparison to a subagent (sonnet). The subagent reads ONLY the two outputs — it does not see the hypothesis or changes. This keeps the comparison unbiased. ``` Task(model: sonnet, subagent_type: general-purpose) Compare these two outputs for quality. You do not know which is "old" or "new." Output A: /[previous best]/output.md Output B: /iter-N/output.md Quality signal: [from loop.md] Produce: 1. WINNER: A or B or TIE (on the specific quality signal) 2. EVIDENCE: 3-5 specific examples showing why 3. TRADE-OFFS: Did anything get worse in the winner? 4. CONFIDENCE: How clear is the difference? (obvious / marginal / unclear) Write to /iter-N/comparison.md Return: winner + confidence + one-line evidence summary ``` ### Phase 6: VERDICT Based on the comparison summary, update loop state: Write `/iter-N/verdict.md`: ```markdown # Verdict: Iteration N Result: [BETTER / WORSE / MIXED] Confidence: [obvious / marginal / unclear] Evidence: [1-2 lines from comparison] Keep: [what to preserve from this iteration] Revert: [what to undo if anything] ``` Update `loop.md`: - Increment iteration - Update "best so far" - Add to hypothesis log - Add to "what we've learned" - Set "next" — either another hypothesis or CLOSED ### When to close the loop Close when any of these are true: - The quality signal is met (output is good enough) - 3 consecutive iterations show no improvement (diminishing returns) - The user says to stop - The cost of another iteration exceeds the expected improvement Write `/summary.md`: ```markdown # Loop Summary: [description] ## Result Started: [date] Iterations: [N] Best: [iter-N] Status: [closed — quality met / closed — diminishing returns / closed — user stopped] ## What worked - [Changes that improved output, with evidence] ## What didn't work - [Changes that didn't help or made things worse] ## Final state Run command: [the command with all improvements applied] Output quality: [assessment against the original quality signal] ## If reopening later Read iter-[best]/output.md for the current best. The key changes that got us here: [1-2 sentences]. The remaining weakness: [if any]. ``` ## Context Management Rules These are non-negotiable — they're the entire point of using a scratch directory: 1. **Never paste full outputs into the conversation.** They live on disk. Subagents read them from disk. The main conversation sees only summaries. 2. **Never hold more than one iteration's hypothesis + verdict in conversation.** If you need to reference earlier iterations, re-read loop.md — it has the condensed history. 3. **Subagents are stateless.** Each subagent gets pointed at specific files on disk. They don't inherit conversation context. This is a feature — it prevents context buildup. 4. **loop.md is the resumption point.** If the conversation compacts or a new session starts, loop.md + the iteration folders contain everything needed to continue. 5. **The user sees summaries, not data.** After each phase, report to the user in 2-3 lines: what happened, what the verdict was, what's next. They can dig into the scratch directory if they want details.