From d5c6ef9c1911d6d72b801b65c492b873b0bd45f6 Mon Sep 17 00:00:00 2001 From: Vinod Muthusamy Date: Thu, 30 Apr 2026 14:50:36 -0500 Subject: [PATCH 1/2] fix(learn): read saved trajectory with Read tool, drop live-transcript fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The forked learn skill was being told to `cat ` on the live session file under ~/.claude/projects/. That path lives outside the project workspace, so every read triggers a permission prompt; and the file can be large enough that the agent improvises with head/wc/inline `python3 -c` loops, each of which prompts again. Switch SKILL.md Step 0 to a single source: the copy that save-trajectory's Stop hook has already placed at .evolve/trajectories/claude-transcript_.jsonl (inside the project tree, so reads are pre-approved). Instruct the agent to use the Read tool — it pages large files natively and needs no shell helpers. If the saved file is missing, the skill exits with zero entities rather than reaching back into ~/.claude/projects/. on_stop.py drops the "The session transcript is at: …" marker it used to emit; only the "The saved trajectory path is: …" marker remains, so the skill can no longer be tempted to read the live file. --- .../plugins/evolve-lite/skills/learn/SKILL.md | 20 ++++--------------- .../skills/learn/scripts/on_stop.py | 1 - 2 files changed, 4 insertions(+), 17 deletions(-) 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..ffe60057 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 3. -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: 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" From a2a57089c6617dd32470d0faa7701e7337eed26a Mon Sep 17 00:00:00 2001 From: Vinod Muthusamy Date: Thu, 30 Apr 2026 14:58:51 -0500 Subject: [PATCH 2/2] fix(learn): instruct skill to use Glob + Read when reviewing existing guidelines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The forked learn skill was opening prior guidelines via shell for-loops (`for f in .evolve/entities/guideline/*.md; do cat "$f"; done`) so it could extract complementary rather than duplicate findings. Every iteration triggered a permission prompt. Add an explicit Step 2 ("Review Existing Guidelines") that names the intent, requires Glob to enumerate and Read to open each file, and forbids `cat` / `head` / `find` / `for` / `python3 -c` on the entity tree. Renumber the subsequent steps (Extract → 3, Save → 4) and fix the Step 0 cross-reference to match. --- .../plugins/evolve-lite/skills/learn/SKILL.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) 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 ffe60057..21e70613 100644 --- a/platform-integrations/claude/plugins/evolve-lite/skills/learn/SKILL.md +++ b/platform-integrations/claude/plugins/evolve-lite/skills/learn/SKILL.md @@ -29,7 +29,7 @@ This skill analyzes the current conversation to extract guidelines that **correc 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 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 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. **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. @@ -47,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. @@ -65,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.