diff --git a/platform-integrations/claude/plugins/evolve-lite/skills/learn/SKILL.md b/platform-integrations/claude/plugins/evolve-lite/skills/learn/SKILL.md index 5c3a8100..21e70613 100644 --- a/platform-integrations/claude/plugins/evolve-lite/skills/learn/SKILL.md +++ b/platform-integrations/claude/plugins/evolve-lite/skills/learn/SKILL.md @@ -27,28 +27,16 @@ This skill analyzes the current conversation to extract guidelines that **correc ### Step 0: Load the Conversation -This skill runs in a forked context with no access to the parent conversation. The stop hook message (produced by `on_stop.py`) contains two literal markers: +This skill runs in a forked context with no access to the parent conversation. The stop-hook message (produced by `on_stop.py`) contains one literal marker: -- `The session transcript is at: ` — the live session transcript. Take everything between that marker and the next marker (or end of message), strip whitespace and quotes, and use the result as `transcript_path`. -- `The saved trajectory path is: ` — the relative path of the saved trajectory copy under `.evolve/trajectories/`. Extract this the same way and remember it as `saved_trajectory_path` — you will attach it to each entity in Step 3. +- `The saved trajectory path is: ` — a copy of the session transcript saved inside the project tree at `.evolve/trajectories/claude-transcript_.jsonl`. Take everything after the colon, strip surrounding whitespace and quotes, and use the result as `saved_trajectory_path`. You will also attach this exact path to each entity's `trajectory` field in Step 4. -Then read the session transcript: +**Read this file with the `Read` tool — do NOT shell out.** `Read` pages large files natively (use its `offset` / `limit` parameters if needed). Do not use `cat`, `head`, `wc`, `find`, or `python3 -c` loops on the transcript — those trigger a permission prompt for every invocation and are unnecessary. -```bash -cat -``` - -**You must read this file to analyze the conversation** — the forked context has no other access to it. +If the saved trajectory file does not exist (e.g., the save-trajectory hook did not run, or no marker was provided), output zero entities and exit. Do NOT fall back to reading the live session transcript under `~/.claude/projects/` — that path is outside the project tree, triggers permission prompts, and may be larger than the fork can consume. The transcript is JSONL: each line is a separate JSON object. Focus on lines where `"type": "assistant"` or `"type": "human"` to reconstruct the conversation flow. Look for tool calls, errors in tool results, and user corrections. -If no transcript path was provided, fall back to `.evolve/trajectories/`, which may contain either format: - -- **`trajectory_*.json`** — a single JSON object with `messages: [{role, content}, …]`. Prefer the most recent one; parse with `json.load`. -- **`claude-transcript_*.jsonl`** — raw Claude JSONL (same format as the primary `transcript_path`). Parse line-by-line. - -If no transcript is available at all, output zero entities. - ### Step 1: Analyze the Conversation Review the conversation (loaded from the transcript) and identify: @@ -59,7 +47,19 @@ Review the conversation (loaded from the transcript) and identify: If none of these occurred, **output zero entities**. Not every conversation produces guidelines. -### Step 2: Extract Entities +### Step 2: Review Existing Guidelines + +Before extracting, look at what has already been saved for this project. Earlier Stop hooks in the same session (or prior sessions) may have recorded guidelines that cover the same ground — re-extracting them is wasteful and pollutes the library. + +Use the **Glob tool** to enumerate existing guideline files: `.evolve/entities/**/*.md`. Then use the **Read tool** to open each match and skim the content + trigger. + +**Do NOT use `cat`, `head`, `find`, a `for` loop, or an inline `python3 -c` script for this.** Each shell invocation triggers a permission prompt, and Glob + Read cover the same need without any prompting. + +If there are no existing guidelines, skip this step. + +With the existing-guideline set in mind, when you proceed to Step 3 you should pick only *complementary* findings — new angles, new failure modes, or finer-grained detail — and drop candidates that restate or near-duplicate anything already saved. (`save_entities.py` will also drop exact-match duplicates at write time, but it cannot catch re-wordings.) + +### Step 3: Extract Entities For each identified shortcut, error, or user correction, create one entity — up to 5 entities; output 0 when none qualify. If more candidates exist, keep only the highest-impact ones. @@ -77,7 +77,7 @@ Principles: 4. **For user corrections, use the user's own words** — preserve the specific preference rather than generalizing it -### Step 3: Save Entities +### Step 4: Save Entities Output entities as JSON and pipe to the save script. The `type` field must always be `"guideline"` — no other types are accepted. Include a `trajectory` field on every entity, set to the `saved_trajectory_path` extracted in Step 0 — this records which session produced the guideline. diff --git a/platform-integrations/claude/plugins/evolve-lite/skills/learn/scripts/on_stop.py b/platform-integrations/claude/plugins/evolve-lite/skills/learn/scripts/on_stop.py index f769c483..d26afbcb 100644 --- a/platform-integrations/claude/plugins/evolve-lite/skills/learn/scripts/on_stop.py +++ b/platform-integrations/claude/plugins/evolve-lite/skills/learn/scripts/on_stop.py @@ -18,7 +18,6 @@ def main(): transcript_path = input_data.get("transcript_path", "") reason = "Run the /evolve-lite:learn skill." if transcript_path: - reason += f" The session transcript is at: {transcript_path}" session_id = Path(transcript_path).stem.removeprefix("claude-transcript_") if session_id: saved_trajectory = f".evolve/trajectories/claude-transcript_{session_id}.jsonl"