From 0a9bf220c76bf8399b4afc5f7d6ba56c6c642ef1 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:31:54 +0530 Subject: [PATCH 01/36] Wire the no cluster and force flags into the build skill Step 2 suggested a no cluster shortcut for a flat corpus and the number 479 shrink guard error suggested a forced rebuild, but neither flag was ever implemented: Step 4 called cluster() unconditionally and to_json() never received force=, so both were ghost flags the skill referenced but could not act on. Step 4 now builds a single "Full Corpus" community instead of calling cluster() when the no cluster flag was given, both to_json() calls take force=IS_FORCE, and Step 5 is skipped when there is only one placeholder community to not label. Applied to the core fragment and both hand maintained monoliths, with a new sanctioned diff predicate in gen.py's monolith round trip guard for the deliberate change. Co-Authored-By: Claude Sonnet 5 --- tools/skillgen/fragments/core/aider.md | 19 +++++++++++----- tools/skillgen/fragments/core/core.md | 21 ++++++++++++----- tools/skillgen/fragments/core/devin.md | 19 +++++++++++----- tools/skillgen/gen.py | 31 ++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 15 deletions(-) diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 4996beb787..4190b64b8c 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -15,6 +15,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --mode deep # thorough extraction, richer INFERRED edges /graphify --update # incremental - re-extract only new/changed files /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -389,6 +391,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source->target), otherwise `False` (the default undirected `Graph`). Substitute it everywhere it appears, the same way you substitute `INPUT_PATH` - do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given, otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -410,19 +414,22 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) @@ -447,6 +454,8 @@ Replace INPUT_PATH with the actual path. ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) - there is only one placeholder community ("Full Corpus"), nothing to label. + Read `.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -482,7 +491,7 @@ Path('.graphify_labels.json').write_text(json.dumps({str(k): v for k, v in label # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') print('Report updated with community labels') diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index c527a12563..0a24cf7e81 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -17,6 +17,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -329,6 +331,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -352,20 +356,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -416,6 +425,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -452,7 +463,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index f9be846cbf..54083bf523 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -25,6 +25,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --mode deep # thorough extraction, richer INFERRED edges /graphify --update # incremental - re-extract only new/changed files /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -454,6 +456,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source->target), otherwise `False` (the default undirected `Graph`). Substitute it everywhere it appears, the same way you substitute `INPUT_PATH` - do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given, otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -475,19 +479,22 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) @@ -512,6 +519,8 @@ Replace INPUT_PATH with the actual path. ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) - there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -547,7 +556,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') print('Report updated with community labels') diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 09e19ede00..d43d863da8 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1142,6 +1142,36 @@ def _is_community_label_export_fix_line(line: str) -> bool: ) +def _is_no_cluster_force_fix_line(line: str) -> bool: + """Whether a line is part of the --no-cluster / --force wiring fix (#1619 C1/C2). + + Step 2 suggested --no-cluster and the #479 shrink-guard error message + suggested --force, but neither flag was ever implemented: Step 4 called + cluster() unconditionally, and to_json() never received force=. Both are + now wired through -- Step 4 builds a single "Full Corpus" community + instead of calling cluster() when --no-cluster was given, both to_json() + calls take force=IS_FORCE, and Step 5 is skipped when there is nothing to + label. These are the added Usage lines, the substitution instructions, + and the changed Step 4/5 body lines (old and new forms both sanctioned, + matched trimmed so the added lines' extra indentation inside the new + if/else does not matter). + """ + stripped = line.strip() + return ( + stripped.startswith('/graphify --no-cluster ') + or stripped.startswith('/graphify --force ') + or stripped.startswith("Two more substitutions, in this step's block and Step 5's:") + or stripped == "if IS_NO_CLUSTER:" + or stripped == "communities = {0: list(G.nodes())}" + or stripped == "communities = cluster(G)" + or stripped + == "labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities}" + or stripped == "labels = {cid: 'Community ' + str(cid) for cid in communities}" + or "regenerated with real labels in Step 5" in line + or "Skip this step entirely if `--no-cluster` was given in Step 4" in line + ) + + # Every line that may differ between a rendered monolith and its pristine v8 # baseline. Each predicate documents one sanctioned change-class; a blank line is # allowed because the multi-line fix blocks insert spacing. Anything else failing @@ -1163,6 +1193,7 @@ def _is_community_label_export_fix_line(line: str) -> bool: _is_uv_from_interpreter_fix_line, _is_semantic_cache_scope_fix_line, _is_community_label_export_fix_line, + _is_no_cluster_force_fix_line, ) From c8c2fc3d43ccc358e5020e821979a0ae747f1d25 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:32:03 +0530 Subject: [PATCH 02/36] Regenerate skill artifacts for the no cluster and force fix Co-Authored-By: Claude Sonnet 5 --- graphify/skill-agents.md | 21 ++++++++++++++----- graphify/skill-aider.md | 19 ++++++++++++----- graphify/skill-amp.md | 21 ++++++++++++++----- graphify/skill-claw.md | 21 ++++++++++++++----- graphify/skill-codex.md | 21 ++++++++++++++----- graphify/skill-copilot.md | 21 ++++++++++++++----- graphify/skill-devin.md | 19 ++++++++++++----- graphify/skill-droid.md | 21 ++++++++++++++----- graphify/skill-kilo.md | 21 ++++++++++++++----- graphify/skill-kiro.md | 21 ++++++++++++++----- graphify/skill-opencode.md | 21 ++++++++++++++----- graphify/skill-pi.md | 21 ++++++++++++++----- graphify/skill-trae.md | 21 ++++++++++++++----- graphify/skill-vscode.md | 21 ++++++++++++++----- graphify/skill-windows.md | 21 ++++++++++++++----- graphify/skill.md | 21 ++++++++++++++----- .../expected/graphify__skill-agents.md | 21 ++++++++++++++----- .../expected/graphify__skill-aider.md | 19 ++++++++++++----- .../skillgen/expected/graphify__skill-amp.md | 21 ++++++++++++++----- .../skillgen/expected/graphify__skill-claw.md | 21 ++++++++++++++----- .../expected/graphify__skill-codex.md | 21 ++++++++++++++----- .../expected/graphify__skill-copilot.md | 21 ++++++++++++++----- .../expected/graphify__skill-devin.md | 19 ++++++++++++----- .../expected/graphify__skill-droid.md | 21 ++++++++++++++----- .../skillgen/expected/graphify__skill-kilo.md | 21 ++++++++++++++----- .../skillgen/expected/graphify__skill-kiro.md | 21 ++++++++++++++----- .../expected/graphify__skill-opencode.md | 21 ++++++++++++++----- tools/skillgen/expected/graphify__skill-pi.md | 21 ++++++++++++++----- .../skillgen/expected/graphify__skill-trae.md | 21 ++++++++++++++----- .../expected/graphify__skill-vscode.md | 21 ++++++++++++++----- .../expected/graphify__skill-windows.md | 21 ++++++++++++++----- tools/skillgen/expected/graphify__skill.md | 21 ++++++++++++++----- 32 files changed, 504 insertions(+), 160 deletions(-) diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 190827d9ac..ac01ce8555 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 4996beb787..4190b64b8c 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -15,6 +15,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --mode deep # thorough extraction, richer INFERRED edges /graphify --update # incremental - re-extract only new/changed files /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -389,6 +391,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source->target), otherwise `False` (the default undirected `Graph`). Substitute it everywhere it appears, the same way you substitute `INPUT_PATH` - do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given, otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -410,19 +414,22 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) @@ -447,6 +454,8 @@ Replace INPUT_PATH with the actual path. ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) - there is only one placeholder community ("Full Corpus"), nothing to label. + Read `.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -482,7 +491,7 @@ Path('.graphify_labels.json').write_text(json.dumps({str(k): v for k, v in label # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') print('Report updated with community labels') diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 190827d9ac..ac01ce8555 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index abd2811d23..b75bc83cc2 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index af3f723c78..91587ce727 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index abd2811d23..b75bc83cc2 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index f9be846cbf..54083bf523 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -25,6 +25,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --mode deep # thorough extraction, richer INFERRED edges /graphify --update # incremental - re-extract only new/changed files /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -454,6 +456,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source->target), otherwise `False` (the default undirected `Graph`). Substitute it everywhere it appears, the same way you substitute `INPUT_PATH` - do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given, otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -475,19 +479,22 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) @@ -512,6 +519,8 @@ Replace INPUT_PATH with the actual path. ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) - there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -547,7 +556,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') print('Report updated with community labels') diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index fd148d485d..9baca3ec6f 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index 3e70b050a4..cb219fc1e9 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index abd2811d23..b75bc83cc2 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 91ced60675..69c4656edb 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -386,6 +388,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -409,20 +413,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -473,6 +482,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -509,7 +520,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index abd2811d23..b75bc83cc2 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 050667bc20..993340310e 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -392,6 +394,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -415,20 +419,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -479,6 +488,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -515,7 +526,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 20c7c0835c..5d7f1243f7 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -390,6 +392,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -413,20 +417,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -477,6 +486,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -513,7 +524,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index 764c1914d9..e1573b21a9 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -421,6 +423,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast["nodes"])} AST + {len(sem **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```powershell New-Item -ItemType Directory -Force -Path graphify-out | Out-Null @' @@ -444,20 +448,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -508,6 +517,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -544,7 +555,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill.md b/graphify/skill.md index abd2811d23..b75bc83cc2 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 190827d9ac..ac01ce8555 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 4996beb787..4190b64b8c 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -15,6 +15,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --mode deep # thorough extraction, richer INFERRED edges /graphify --update # incremental - re-extract only new/changed files /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -389,6 +391,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source->target), otherwise `False` (the default undirected `Graph`). Substitute it everywhere it appears, the same way you substitute `INPUT_PATH` - do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given, otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -410,19 +414,22 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) @@ -447,6 +454,8 @@ Replace INPUT_PATH with the actual path. ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) - there is only one placeholder community ("Full Corpus"), nothing to label. + Read `.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -482,7 +491,7 @@ Path('.graphify_labels.json').write_text(json.dumps({str(k): v for k, v in label # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') print('Report updated with community labels') diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 190827d9ac..ac01ce8555 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index abd2811d23..b75bc83cc2 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index af3f723c78..91587ce727 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index abd2811d23..b75bc83cc2 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index f9be846cbf..54083bf523 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -25,6 +25,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --mode deep # thorough extraction, richer INFERRED edges /graphify --update # incremental - re-extract only new/changed files /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -454,6 +456,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source->target), otherwise `False` (the default undirected `Graph`). Substitute it everywhere it appears, the same way you substitute `INPUT_PATH` - do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given, otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -475,19 +479,22 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) @@ -512,6 +519,8 @@ Replace INPUT_PATH with the actual path. ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) - there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -547,7 +556,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') print('Report updated with community labels') diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index fd148d485d..9baca3ec6f 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -391,6 +393,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -414,20 +418,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -478,6 +487,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -514,7 +525,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index 3e70b050a4..cb219fc1e9 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index abd2811d23..b75bc83cc2 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index 91ced60675..69c4656edb 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -386,6 +388,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -409,20 +413,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -473,6 +482,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -509,7 +520,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index abd2811d23..b75bc83cc2 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 050667bc20..993340310e 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -392,6 +394,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -415,20 +419,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -479,6 +488,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -515,7 +526,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 20c7c0835c..5d7f1243f7 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -390,6 +392,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -413,20 +417,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -477,6 +486,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -513,7 +524,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index 764c1914d9..e1573b21a9 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -421,6 +423,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast["nodes"])} AST + {len(sem **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```powershell New-Item -ItemType Directory -Force -Path graphify-out | Out-Null @' @@ -444,20 +448,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -508,6 +517,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -544,7 +555,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index abd2811d23..b75bc83cc2 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -20,6 +20,8 @@ Turn any folder of files into a navigable knowledge graph with community detecti /graphify --directed # build directed graph (preserves edge direction: source→target) /graphify --whisper-model medium # use a larger Whisper model for better transcription accuracy /graphify --cluster-only # rerun clustering on existing graph +/graphify --no-cluster # skip clustering, one "Full Corpus" community (flat/small corpora) +/graphify --force # allow the rebuild to shrink graph.json (e.g. after deleting files) /graphify --no-viz # skip visualization, just report + JSON /graphify --html # (HTML is generated by default - this flag is a no-op) /graphify --svg # also export graph.svg (embeds in Notion, GitHub) @@ -394,6 +396,8 @@ print(f'Merged: {total} nodes, {edges} edges ({len(ast[\"nodes\"])} AST + {len(s **Before starting:** the code blocks below pass `directed=IS_DIRECTED` to `build_from_json()`. Replace `IS_DIRECTED` with `True` if `--directed` was given (builds a `DiGraph` preserving edge direction source→target), otherwise `False` (the default undirected `Graph`). Substitute it the same way you substitute `INPUT_PATH` — do not leave the literal `IS_DIRECTED` in the code. +Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTER` with `True` if `--no-cluster` was given (explicitly, or accepted after Step 2 suggested it for a flat corpus), otherwise `False`. Replace `IS_FORCE` with `True` if `--force` was given, otherwise `False`. + ```bash mkdir -p graphify-out $(cat graphify-out/.graphify_python) -c " @@ -417,20 +421,25 @@ if G.number_of_nodes() == 0: print('ERROR: Graph is empty - extraction produced no nodes.') print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.') raise SystemExit(1) -communities = cluster(G) +if IS_NO_CLUSTER: + # Skip the expensive clustering step entirely - one placeholder community + # covering every node, per Step 2's flat-corpus suggestion. + communities = {0: list(G.nodes())} +else: + communities = cluster(G) cohesion = score_all(G, communities) tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)} gods = god_nodes(G) surprises = surprising_connections(G, communities) -labels = {cid: 'Community ' + str(cid) for cid in communities} -# Placeholder questions - regenerated with real labels in Step 5 +labels = {0: 'Full Corpus'} if IS_NO_CLUSTER else {cid: 'Community ' + str(cid) for cid in communities} +# Placeholder questions - regenerated with real labels in Step 5 (skipped for --no-cluster) questions = suggest_questions(G, communities, labels) # Export FIRST and honor the #479 shrink-guard: to_json returns False (writing # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json') +wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') @@ -481,6 +490,8 @@ Substitute `IS_DIRECTED` and `INPUT_PATH` as in Step 4. If a `GRAPH HEALTH WARNI ### Step 5 - Label communities +Skip this step entirely if `--no-cluster` was given in Step 4 (`IS_NO_CLUSTER` was `True`) — there is only one placeholder community ("Full Corpus"), nothing to label. + Read `graphify-out/.graphify_analysis.json`. For each community key, look at its node labels and write a 2-5 word plain-language name (e.g. "Attention Mechanism", "Training Pipeline", "Data Loading"). Then regenerate the report and save the labels for the visualizer: @@ -517,7 +528,7 @@ Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for # Re-export so graph.json nodes carry the curated community_name (#2490). # Same extraction as Step 4, so the #479 shrink-guard passes on node count; # if it still refuses, surface the guard message - do not force past it. -wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels) +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') From ab14af64a3d6566609c95a9f7fb20675acf761a3 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:32:03 +0530 Subject: [PATCH 03/36] Add regression tests for the no cluster and force wiring Covers the core render plus both monoliths: Usage lists both flags, Step 4 branches on the no cluster substitution instead of always clustering, both to_json calls receive the force substitution, and Step 5 documents skipping labeling when there is nothing to label. Updates the two existing literal string assertions that pinned the pre fix Step 5 to_json call verbatim. Co-Authored-By: Claude Sonnet 5 --- tests/test_community_labels_skill.py | 4 ++-- tests/test_skillgen.py | 36 +++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/tests/test_community_labels_skill.py b/tests/test_community_labels_skill.py index 5184190e94..dc4b702171 100644 --- a/tests/test_community_labels_skill.py +++ b/tests/test_community_labels_skill.py @@ -101,7 +101,7 @@ def test_skill_step5_reexports_graph_json_with_curated_labels(path: Path): ] assert post_labels_blocks, f"{path.name}: no Step-5 (LABELS_DICT) code block found" for block in post_labels_blocks: - assert "to_json(G, communities, 'graphify-out/graph.json', community_labels=labels)" in block, ( + assert "to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE)" in block, ( f"{path.name}: the post-labels Step-5 block must re-export " f"graphify-out/graph.json with community_labels=labels (#2490)" ) @@ -125,7 +125,7 @@ def test_core_fragments_step5_reexport_with_curated_labels(fragment: Path): ] assert post_labels_blocks, f"{fragment.name}: no Step-5 (LABELS_DICT) code block found" for block in post_labels_blocks: - assert "to_json(G, communities, 'graphify-out/graph.json', community_labels=labels)" in block, ( + assert "to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE)" in block, ( f"{fragment.name}: the post-labels Step-5 block must re-export " f"graphify-out/graph.json with community_labels=labels (#2490)" ) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index ab6f94474c..869d82017d 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -416,7 +416,7 @@ def test_windows_and_posix_cores_have_step_and_2490_parity(): for heading in _STEP_HEADINGS: assert heading in claude_core, f"skill.md lost step heading: {heading!r}" assert heading in windows_core, f"skill-windows.md lost step heading: {heading!r}" - line_2490 = "to_json(G, communities, 'graphify-out/graph.json', community_labels=labels)" + line_2490 = "to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE)" assert line_2490 in claude_core, "skill.md lost the #2490 Step-5 re-export" assert line_2490 in windows_core, "skill-windows.md lost the #2490 Step-5 re-export" @@ -651,6 +651,40 @@ def test_monoliths_carry_the_1392_runbook_fixes(): assert "if not wrote:" in body +def test_no_cluster_and_force_flags_are_wired_through(): + """#1619 C1/C2: --no-cluster and --force were documented/suggested but never + implemented -- cluster() ran unconditionally and to_json() never received + force=. Both are now wired through Step 4/5, for the core render and both + hand-maintained monoliths. + """ + claude_core, _ = _platform_artifacts("claude") + platforms = gen.load_platforms() + bodies = {"claude": claude_core} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + assert "--no-cluster" in body.split("## Usage")[1].split("```")[1], ( + f"[{key}] --no-cluster missing from Usage" + ) + assert "--force " in body.split("## Usage")[1].split("```")[1], ( + f"[{key}] --force missing from Usage" + ) + assert "if IS_NO_CLUSTER:" in body, f"[{key}] Step 4 does not branch on IS_NO_CLUSTER" + assert "communities = {0: list(G.nodes())}" in body, ( + f"[{key}] Step 4 missing the flat --no-cluster community shortcut" + ) + assert "force=IS_FORCE" in body, f"[{key}] to_json is not wired to IS_FORCE" + # Both to_json(...graph.json...) calls in the main build path take it - + # Step 4's first write and Step 5's curated-labels re-export. + assert body.count("force=IS_FORCE") >= 2, ( + f"[{key}] expected force=IS_FORCE on both Step 4 and Step 5 to_json calls" + ) + assert "Skip this step entirely if `--no-cluster` was given in Step 4" in body, ( + f"[{key}] Step 5 does not document skipping labeling for --no-cluster" + ) + + def test_monoliths_scope_semantic_cache_writes_to_uncached_files(): """#1757: generated monoliths pass the dispatched-file allowlist when replacing semantic cache entries.""" From f23b059f3e54b72545c5780098e36d21a813f2a1 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:32:03 +0530 Subject: [PATCH 04/36] Add changelog entry for issue 1619 Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0daf515f..4b20ca4732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu ## 0.9.63 (2026-09-16) +- Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label (#1619, thanks @edtrackai). - Feature: Elixir `alias`/`import`/`require`/`use` targets now resolve onto the module's `defmodule` node across files, so the internal module dependency graph is no longer dropped as dangling. Only top-level modules are indexed (a nested `defmodule`, labeled with its bare inner name, cannot capture an unrelated `use ` from another file), and a same-file reference is left unresolved so it cannot clobber the structural `contains` edge (#3603, thanks @ayushcodes10). - Feature: a Rust `self.method()` call now resolves to a method defined on the same type in another file (the common split-`impl`-block layout), pooling methods across every `impl` of one type and refusing to link when two unrelated types share a bare name (#3602, thanks @ayushcodes10). - Feature: a Ruby member call `obj.foo` on a known-type receiver now resolves to a method `foo` inherited from a superclass, including across files, using the same conservative promotion as the implicit-self resolver — a single owning class, matching method kind, and one unambiguous ancestry chain, or it stays dangling (#3585, thanks @oleksii-tumanov). From 2f7f4dd48f68dc9cc3a73b7b486338d35df85e13 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:38:09 +0530 Subject: [PATCH 05/36] Substitute INPUT_PATH with forward slashes on Windows A Windows path pasted in with backslashes splices a stray escape into the Python string literal INPUT_PATH is substituted into: a lone t becomes a tab and a lone U raises a syntax error, corrupting the block silently or loudly. One rule near the top of each host now tells the agent to substitute forward slashes instead, and the PowerShell Resolve Path call that saves the scan root is now quoted so a path containing a space survives too. Co-Authored-By: Claude Sonnet 5 --- tools/skillgen/fragments/core/aider.md | 2 ++ tools/skillgen/fragments/core/core.md | 2 ++ tools/skillgen/fragments/core/devin.md | 2 ++ tools/skillgen/fragments/shell/powershell.md | 2 +- tools/skillgen/gen.py | 13 +++++++++++++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 4190b64b8c..1295638b47 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + Follow these steps in order. Do not skip steps. ### Step 1 - Ensure graphify is installed diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index 0a24cf7e81..91125759cc 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -53,6 +53,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 54083bf523..4938011189 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -67,6 +67,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + Follow these steps in order. Do not skip steps. ### Step 1 - Ensure graphify is installed diff --git a/tools/skillgen/fragments/shell/powershell.md b/tools/skillgen/fragments/shell/powershell.md index 71e493cf8d..dda0cbeb52 100644 --- a/tools/skillgen/fragments/shell/powershell.md +++ b/tools/skillgen/fragments/shell/powershell.md @@ -58,7 +58,7 @@ if (-not $GRAPHIFY_PYTHON) { $Utf8NoBom = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_python'), [string]$GRAPHIFY_PYTHON, $Utf8NoBom) # Save scan root so `graphify update` (no args) knows where to look next time -[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path INPUT_PATH).Path, $Utf8NoBom) +[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path 'INPUT_PATH').Path, $Utf8NoBom) ``` If the import succeeds, print nothing and move straight to Step 2. diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index d43d863da8..eea283311a 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1172,6 +1172,18 @@ def _is_no_cluster_force_fix_line(line: str) -> bool: ) +def _is_input_path_slash_guidance_line(line: str) -> bool: + """Whether a line is the #1619 B1 forward-slash INPUT_PATH guidance. + + A Windows path substituted into INPUT_PATH splices raw backslashes into a + Python string literal (`\\t` becomes a tab, `\\U` raises a SyntaxError), + silently or loudly corrupting the block. One rule near the top of each + monolith, right after the path-resolution paragraph it belongs with, + tells the agent to substitute with forward slashes instead. + """ + return "substitute it with forward slashes" in line.lower() + + # Every line that may differ between a rendered monolith and its pristine v8 # baseline. Each predicate documents one sanctioned change-class; a blank line is # allowed because the multi-line fix blocks insert spacing. Anything else failing @@ -1194,6 +1206,7 @@ def _is_no_cluster_force_fix_line(line: str) -> bool: _is_semantic_cache_scope_fix_line, _is_community_label_export_fix_line, _is_no_cluster_force_fix_line, + _is_input_path_slash_guidance_line, ) From 9fab00f3940ccecbc41eea502ac2595840abe806 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:38:15 +0530 Subject: [PATCH 06/36] Regenerate skill artifacts for the INPUT_PATH slash fix Co-Authored-By: Claude Sonnet 5 --- graphify/skill-agents.md | 2 ++ graphify/skill-aider.md | 2 ++ graphify/skill-amp.md | 2 ++ graphify/skill-claw.md | 2 ++ graphify/skill-codex.md | 2 ++ graphify/skill-copilot.md | 2 ++ graphify/skill-devin.md | 2 ++ graphify/skill-droid.md | 2 ++ graphify/skill-kilo.md | 2 ++ graphify/skill-kiro.md | 2 ++ graphify/skill-opencode.md | 2 ++ graphify/skill-pi.md | 2 ++ graphify/skill-trae.md | 2 ++ graphify/skill-vscode.md | 2 ++ graphify/skill-windows.md | 4 +++- graphify/skill.md | 2 ++ tools/skillgen/expected/graphify__skill-agents.md | 2 ++ tools/skillgen/expected/graphify__skill-aider.md | 2 ++ tools/skillgen/expected/graphify__skill-amp.md | 2 ++ tools/skillgen/expected/graphify__skill-claw.md | 2 ++ tools/skillgen/expected/graphify__skill-codex.md | 2 ++ tools/skillgen/expected/graphify__skill-copilot.md | 2 ++ tools/skillgen/expected/graphify__skill-devin.md | 2 ++ tools/skillgen/expected/graphify__skill-droid.md | 2 ++ tools/skillgen/expected/graphify__skill-kilo.md | 2 ++ tools/skillgen/expected/graphify__skill-kiro.md | 2 ++ tools/skillgen/expected/graphify__skill-opencode.md | 2 ++ tools/skillgen/expected/graphify__skill-pi.md | 2 ++ tools/skillgen/expected/graphify__skill-trae.md | 2 ++ tools/skillgen/expected/graphify__skill-vscode.md | 2 ++ tools/skillgen/expected/graphify__skill-windows.md | 4 +++- tools/skillgen/expected/graphify__skill.md | 2 ++ 32 files changed, 66 insertions(+), 2 deletions(-) diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index ac01ce8555..167785ff36 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 4190b64b8c..1295638b47 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + Follow these steps in order. Do not skip steps. ### Step 1 - Ensure graphify is installed diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index ac01ce8555..167785ff36 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index b75bc83cc2..ad0b1b4618 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index 91587ce727..8a52daf2b0 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index b75bc83cc2..ad0b1b4618 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 54083bf523..4938011189 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -67,6 +67,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + Follow these steps in order. Do not skip steps. ### Step 1 - Ensure graphify is installed diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index 9baca3ec6f..4056892854 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index cb219fc1e9..4b3e24d439 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index b75bc83cc2..ad0b1b4618 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 69c4656edb..dc434d469b 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index b75bc83cc2..ad0b1b4618 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 993340310e..5b0cd60c34 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 5d7f1243f7..6bdfa65ea2 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index e1573b21a9..f3f8934edd 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. @@ -126,7 +128,7 @@ if (-not $GRAPHIFY_PYTHON) { $Utf8NoBom = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_python'), [string]$GRAPHIFY_PYTHON, $Utf8NoBom) # Save scan root so `graphify update` (no args) knows where to look next time -[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path INPUT_PATH).Path, $Utf8NoBom) +[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path 'INPUT_PATH').Path, $Utf8NoBom) ``` If the import succeeds, print nothing and move straight to Step 2. diff --git a/graphify/skill.md b/graphify/skill.md index b75bc83cc2..ad0b1b4618 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index ac01ce8555..167785ff36 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 4190b64b8c..1295638b47 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + Follow these steps in order. Do not skip steps. ### Step 1 - Ensure graphify is installed diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index ac01ce8555..167785ff36 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index b75bc83cc2..ad0b1b4618 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index 91587ce727..8a52daf2b0 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index b75bc83cc2..ad0b1b4618 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 54083bf523..4938011189 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -67,6 +67,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + Follow these steps in order. Do not skip steps. ### Step 1 - Ensure graphify is installed diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index 9baca3ec6f..4056892854 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index cb219fc1e9..4b3e24d439 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index b75bc83cc2..ad0b1b4618 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index 69c4656edb..dc434d469b 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index b75bc83cc2..ad0b1b4618 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 993340310e..5b0cd60c34 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 5d7f1243f7..6bdfa65ea2 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index e1573b21a9..f3f8934edd 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. @@ -126,7 +128,7 @@ if (-not $GRAPHIFY_PYTHON) { $Utf8NoBom = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_python'), [string]$GRAPHIFY_PYTHON, $Utf8NoBom) # Save scan root so `graphify update` (no args) knows where to look next time -[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path INPUT_PATH).Path, $Utf8NoBom) +[System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path 'INPUT_PATH').Path, $Utf8NoBom) ``` If the import succeeds, print nothing and move straight to Step 2. diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index b75bc83cc2..ad0b1b4618 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -56,6 +56,8 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. + If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. Follow these steps in order. Do not skip steps. From 0b561ab434b63f2cdec197d87dee2bf240121539 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:38:15 +0530 Subject: [PATCH 07/36] Add a regression test for the INPUT_PATH slash guidance Checks every host for the forward slash substitution rule and asserts the Windows Resolve Path call is quoted, not just the unquoted form being gone. Co-Authored-By: Claude Sonnet 5 --- tests/test_skillgen.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index 869d82017d..c2c662ecfa 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -685,6 +685,31 @@ def test_no_cluster_and_force_flags_are_wired_through(): ) +def test_input_path_forward_slash_guidance_is_present(): + """#1619 B1: a Windows INPUT_PATH substitution with backslashes corrupts + the Python string literal it's spliced into. Every host must tell the + agent to substitute forward slashes instead, and the PowerShell + Resolve-Path call must be quoted so a path with a space in it survives.""" + claude_core, _ = _platform_artifacts("claude") + windows_core, _ = _platform_artifacts("windows") + platforms = gen.load_platforms() + bodies = {"claude": claude_core, "windows": windows_core} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + assert "substitute it with forward slashes" in body.lower(), ( + f"[{key}] missing the forward-slash INPUT_PATH guidance" + ) + + assert "(Resolve-Path 'INPUT_PATH')" in bodies["windows"], ( + "skill-windows.md's Resolve-Path call must be quoted (#1619 B1)" + ) + assert "(Resolve-Path INPUT_PATH)" not in bodies["windows"], ( + "the unquoted Resolve-Path call must not survive" + ) + + def test_monoliths_scope_semantic_cache_writes_to_uncached_files(): """#1757: generated monoliths pass the dispatched-file allowlist when replacing semantic cache entries.""" From a8b2f5d2111d4e807b2e2c5d522a374ad12659ac Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:38:34 +0530 Subject: [PATCH 08/36] Add changelog entry for the INPUT_PATH slash fix Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b20ca4732..f7d1afb10a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu ## 0.9.63 (2026-09-16) +- Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell `Resolve-Path` call that saves the scan root is quoted so a path containing a space survives too (#1619, thanks @edtrackai). - Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label (#1619, thanks @edtrackai). - Feature: Elixir `alias`/`import`/`require`/`use` targets now resolve onto the module's `defmodule` node across files, so the internal module dependency graph is no longer dropped as dangling. Only top-level modules are indexed (a nested `defmodule`, labeled with its bare inner name, cannot capture an unrelated `use ` from another file), and a same-file reference is left unresolved so it cannot clobber the structural `contains` edge (#3603, thanks @ayushcodes10). - Feature: a Rust `self.method()` call now resolves to a method defined on the same type in another file (the common split-`impl`-block layout), pooling methods across every `impl` of one type and refusing to link when two unrelated types share a bare name (#3602, thanks @ayushcodes10). From 58038d8f262a8abfec7097e18a7aa10e8be575a1 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:47:10 +0530 Subject: [PATCH 09/36] Add a failure gate to Step 1's interpreter install A failed install left the working interpreter variable pointing at one that still could not import graphify, and nothing checked for it: the step fell through silently, wrote that interpreter's path anyway, and every later step then failed with a cryptic command not found error far from the real cause. Step 1 now re checks the import right after the install attempt and stops with an actionable error naming both install commands instead of continuing. Applied to the shared posix and PowerShell install fragments and both hand maintained monoliths, with a matching sanctioned diff predicate in gen.py's monolith round trip guard. Verified by running the actual generated Step 1 bash block under a fake interpreter and PATH where the import always fails and pip always fails too: it now stops with the new error and exit code instead of writing a broken interpreter path. Co-Authored-By: Claude Sonnet 5 --- tools/skillgen/fragments/core/aider.md | 13 ++++++++- tools/skillgen/fragments/core/devin.md | 13 ++++++++- tools/skillgen/fragments/shell/posix.md | 13 ++++++++- tools/skillgen/fragments/shell/powershell.md | 13 ++++++++- tools/skillgen/gen.py | 30 ++++++++++++++++++++ 5 files changed, 78 insertions(+), 4 deletions(-) diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 1295638b47..0f39a9614a 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -90,13 +90,24 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out "$PYTHON" -c "import sys; open('graphify-out/.graphify_python', 'w', encoding='utf-8').write(sys.executable)" ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 4938011189..90dccf4b6a 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -101,6 +101,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -109,7 +120,7 @@ mkdir -p graphify-out export PYTHONUTF8=1 ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/fragments/shell/posix.md b/tools/skillgen/fragments/shell/posix.md index 3534417d23..68c5dc094b 100644 --- a/tools/skillgen/fragments/shell/posix.md +++ b/tools/skillgen/fragments/shell/posix.md @@ -26,6 +26,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -34,6 +45,6 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/fragments/shell/powershell.md b/tools/skillgen/fragments/shell/powershell.md index dda0cbeb52..8cad678689 100644 --- a/tools/skillgen/fragments/shell/powershell.md +++ b/tools/skillgen/fragments/shell/powershell.md @@ -50,6 +50,17 @@ if (-not $GRAPHIFY_PYTHON) { $GRAPHIFY_PYTHON = Find-GraphifyPython } +# #1619 B4: without this gate, a failed install left $GRAPHIFY_PYTHON $null, +# an empty .graphify_python got written anyway, and every later step then +# failed with a cryptic error far from the real cause instead of a clear one +# here. +if (-not $GRAPHIFY_PYTHON) { + Write-Host "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" + Write-Host " uv tool install graphifyy" + Write-Host " pip install graphifyy" + exit 1 +} + # Save interpreter path — all subsequent steps read this. # `Out-File -Encoding utf8` always writes a BOM on Windows PowerShell 5.1 (utf8NoBOM # only exists from PowerShell 6), and that BOM rides into the saved path, so the hook @@ -61,6 +72,6 @@ $Utf8NoBom = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path 'INPUT_PATH').Path, $Utf8NoBom) ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent block, run Python through the saved interpreter — `& (Get-Content graphify-out\.graphify_python)` in place of a bare `python3` — so every step uses the interpreter that actually has graphify.** diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index eea283311a..22c5125f98 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1172,6 +1172,35 @@ def _is_no_cluster_force_fix_line(line: str) -> bool: ) +def _is_install_failure_gate_fix_line(line: str) -> bool: + """Whether a line is part of the #1619 B4 Step 1 failure gate. + + A failed install used to leave PYTHON pointing at an interpreter that + still could not import graphify, with nothing checking for it: the step + fell through silently, wrote that interpreter's path anyway, and every + later step then failed with a cryptic "-c: command not found" far from + the real cause. An explicit re-check after the install attempt now stops + with an actionable error instead. The extra `fi` (added) and the changed + "If the import succeeds..." sentence (both old and new forms) are + sanctioned here too. + """ + stripped = line.strip() + return ( + stripped == "fi" + or "#1619 B4" in line + or "interpreter that still cannot import graphify" in line + or "silently, writing that interpreter's path anyway" in line + or 'then failed with a cryptic "-c: command not found"' in line + or "cause instead of a clear error here" in line + or stripped == 'if ! "$PYTHON" -c "import graphify" 2>/dev/null; then' + or "could not install or locate a Python interpreter with graphify" in line + or "uv tool install graphifyy" in line + or "python3 -m pip install graphifyy" in line + or stripped == "exit 1" + or stripped.startswith("If the import succeeds, print nothing and move straight to Step 2") + ) + + def _is_input_path_slash_guidance_line(line: str) -> bool: """Whether a line is the #1619 B1 forward-slash INPUT_PATH guidance. @@ -1207,6 +1236,7 @@ def _is_input_path_slash_guidance_line(line: str) -> bool: _is_community_label_export_fix_line, _is_no_cluster_force_fix_line, _is_input_path_slash_guidance_line, + _is_install_failure_gate_fix_line, ) From 3497d9bf4df2ca6409f16fee370d0c8165dd8960 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:47:18 +0530 Subject: [PATCH 10/36] Regenerate skill artifacts for the Step 1 failure gate Co-Authored-By: Claude Sonnet 5 --- graphify/skill-agents.md | 13 ++++++++++++- graphify/skill-aider.md | 13 ++++++++++++- graphify/skill-amp.md | 13 ++++++++++++- graphify/skill-claw.md | 13 ++++++++++++- graphify/skill-codex.md | 13 ++++++++++++- graphify/skill-copilot.md | 13 ++++++++++++- graphify/skill-devin.md | 13 ++++++++++++- graphify/skill-droid.md | 13 ++++++++++++- graphify/skill-kilo.md | 13 ++++++++++++- graphify/skill-kiro.md | 13 ++++++++++++- graphify/skill-opencode.md | 13 ++++++++++++- graphify/skill-pi.md | 13 ++++++++++++- graphify/skill-trae.md | 13 ++++++++++++- graphify/skill-vscode.md | 13 ++++++++++++- graphify/skill-windows.md | 13 ++++++++++++- graphify/skill.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-agents.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-aider.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-amp.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-claw.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-codex.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-copilot.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-devin.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-droid.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-kilo.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-kiro.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-opencode.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-pi.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-trae.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-vscode.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill-windows.md | 13 ++++++++++++- tools/skillgen/expected/graphify__skill.md | 13 ++++++++++++- 32 files changed, 384 insertions(+), 32 deletions(-) diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 167785ff36..cabbd6184e 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 1295638b47..0f39a9614a 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -90,13 +90,24 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out "$PYTHON" -c "import sys; open('graphify-out/.graphify_python', 'w', encoding='utf-8').write(sys.executable)" ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 167785ff36..cabbd6184e 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index ad0b1b4618..de07d94ac5 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index 8a52daf2b0..3de8759fac 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index ad0b1b4618..de07d94ac5 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 4938011189..90dccf4b6a 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -101,6 +101,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -109,7 +120,7 @@ mkdir -p graphify-out export PYTHONUTF8=1 ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index 4056892854..2fb4dfbd80 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index 4b3e24d439..f445e67673 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index ad0b1b4618..de07d94ac5 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index dc434d469b..ee0aca0b06 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index ad0b1b4618..de07d94ac5 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 5b0cd60c34..afca54235e 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 6bdfa65ea2..089116e47d 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index f3f8934edd..c23f256398 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -120,6 +120,17 @@ if (-not $GRAPHIFY_PYTHON) { $GRAPHIFY_PYTHON = Find-GraphifyPython } +# #1619 B4: without this gate, a failed install left $GRAPHIFY_PYTHON $null, +# an empty .graphify_python got written anyway, and every later step then +# failed with a cryptic error far from the real cause instead of a clear one +# here. +if (-not $GRAPHIFY_PYTHON) { + Write-Host "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" + Write-Host " uv tool install graphifyy" + Write-Host " pip install graphifyy" + exit 1 +} + # Save interpreter path — all subsequent steps read this. # `Out-File -Encoding utf8` always writes a BOM on Windows PowerShell 5.1 (utf8NoBOM # only exists from PowerShell 6), and that BOM rides into the saved path, so the hook @@ -131,7 +142,7 @@ $Utf8NoBom = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path 'INPUT_PATH').Path, $Utf8NoBom) ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent block, run Python through the saved interpreter — `& (Get-Content graphify-out\.graphify_python)` in place of a bare `python3` — so every step uses the interpreter that actually has graphify.** diff --git a/graphify/skill.md b/graphify/skill.md index ad0b1b4618..de07d94ac5 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 167785ff36..cabbd6184e 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 1295638b47..0f39a9614a 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -90,13 +90,24 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out "$PYTHON" -c "import sys; open('graphify-out/.graphify_python', 'w', encoding='utf-8').write(sys.executable)" ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 167785ff36..cabbd6184e 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index ad0b1b4618..de07d94ac5 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index 8a52daf2b0..3de8759fac 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index ad0b1b4618..de07d94ac5 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 4938011189..90dccf4b6a 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -101,6 +101,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -109,7 +120,7 @@ mkdir -p graphify-out export PYTHONUTF8=1 ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index 4056892854..2fb4dfbd80 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index 4b3e24d439..f445e67673 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index ad0b1b4618..de07d94ac5 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index dc434d469b..ee0aca0b06 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index ad0b1b4618..de07d94ac5 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 5b0cd60c34..afca54235e 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 6bdfa65ea2..089116e47d 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index f3f8934edd..c23f256398 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -120,6 +120,17 @@ if (-not $GRAPHIFY_PYTHON) { $GRAPHIFY_PYTHON = Find-GraphifyPython } +# #1619 B4: without this gate, a failed install left $GRAPHIFY_PYTHON $null, +# an empty .graphify_python got written anyway, and every later step then +# failed with a cryptic error far from the real cause instead of a clear one +# here. +if (-not $GRAPHIFY_PYTHON) { + Write-Host "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" + Write-Host " uv tool install graphifyy" + Write-Host " pip install graphifyy" + exit 1 +} + # Save interpreter path — all subsequent steps read this. # `Out-File -Encoding utf8` always writes a BOM on Windows PowerShell 5.1 (utf8NoBOM # only exists from PowerShell 6), and that BOM rides into the saved path, so the hook @@ -131,7 +142,7 @@ $Utf8NoBom = New-Object System.Text.UTF8Encoding $false [System.IO.File]::WriteAllText((Join-Path $PWD 'graphify-out\.graphify_root'), (Resolve-Path 'INPUT_PATH').Path, $Utf8NoBom) ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent block, run Python through the saved interpreter — `& (Get-Content graphify-out\.graphify_python)` in place of a bare `python3` — so every step uses the interpreter that actually has graphify.** diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index ad0b1b4618..de07d94ac5 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -96,6 +96,17 @@ if ! "$PYTHON" -c "import graphify" 2>/dev/null; then "$PYTHON" -m pip install graphifyy -q 2>/dev/null \ || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3 fi + # #1619 B4: without this gate, a failed install left PYTHON pointing at an + # interpreter that still cannot import graphify. The step fell through + # silently, writing that interpreter's path anyway, and every later step + # then failed with a cryptic "-c: command not found" far from the real + # cause instead of a clear error here. + if ! "$PYTHON" -c "import graphify" 2>/dev/null; then + echo "ERROR: could not install or locate a Python interpreter with graphify. Try one of:" >&2 + echo " uv tool install graphifyy" >&2 + echo " python3 -m pip install graphifyy" >&2 + exit 1 + fi fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out @@ -104,7 +115,7 @@ mkdir -p graphify-out echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` -If the import succeeds, print nothing and move straight to Step 2. +If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. **In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** From aac205b35c203fbffd74a09b557b17fc54d0ab53 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:47:18 +0530 Subject: [PATCH 11/36] Add a regression test for the Step 1 failure gate Asserts the failure message is present on every host and that it fires before the interpreter path is persisted for later steps to read. Co-Authored-By: Claude Sonnet 5 --- tests/test_skillgen.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index c2c662ecfa..9627f78046 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -710,6 +710,36 @@ def test_input_path_forward_slash_guidance_is_present(): ) +def test_step1_gates_on_a_still_failed_install(): + """#1619 B4: a failed install must stop with an actionable error instead of + silently writing a broken interpreter path that fails every later step + with a cryptic error far from the real cause. + """ + claude_core, _ = _platform_artifacts("claude") + windows_core, _ = _platform_artifacts("windows") + platforms = gen.load_platforms() + bodies = {"claude": claude_core, "windows": windows_core} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + assert "could not install or locate a Python interpreter with graphify" in body, ( + f"[{key}] missing the Step 1 failure-gate error message" + ) + lines = body.splitlines() + gate_i = next( + i for i, l in enumerate(lines) + if "could not install or locate a Python interpreter" in l + ) + write_i = next( + i for i, l in enumerate(lines) + if ".graphify_python" in l and ("write(" in l or "WriteAllText" in l) + ) + # the gate fires after the install attempt, before the (possibly still + # broken) interpreter path is persisted for every later step to read. + assert gate_i < write_i, f"[{key}] Step 1 gate does not precede the interpreter-path write" + + def test_monoliths_scope_semantic_cache_writes_to_uncached_files(): """#1757: generated monoliths pass the dispatched-file allowlist when replacing semantic cache entries.""" From b9229acedd1e2512f1670eb6fbd06c23355b7fcd Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:47:33 +0530 Subject: [PATCH 12/36] Add changelog entry for the Step 1 failure gate Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7d1afb10a..2292472389 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu ## 0.9.63 (2026-09-16) +- Fix: `/graphify` skill Step 1 now stops with an actionable error when the interpreter install still fails after the retry, instead of silently writing a broken interpreter path that every later step then failed against with a cryptic error far removed from the real cause (#1619, thanks @edtrackai). - Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell `Resolve-Path` call that saves the scan root is quoted so a path containing a space survives too (#1619, thanks @edtrackai). - Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label (#1619, thanks @edtrackai). - Feature: Elixir `alias`/`import`/`require`/`use` targets now resolve onto the module's `defmodule` node across files, so the internal module dependency graph is no longer dropped as dangling. Only top-level modules are indexed (a nested `defmodule`, labeled with its bare inner name, cannot capture an unrelated `use ` from another file), and a same-file reference is left unresolved so it cannot clobber the structural `contains` edge (#3603, thanks @ayushcodes10). From fa1eae4bec904e64f0ac5ace6ffe4f36dc343ca9 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:55:29 +0530 Subject: [PATCH 13/36] Move the update backup instruction before the merge it backs up The old graph backup instruction appeared after both the merge block and the diff block that reads the backup, so an agent reading the runbook top to bottom never created the backup file before the merge ran. The diff block's presence check on that file then silently found nothing and skipped the diff on every single update, instead of only when a backup was genuinely unavailable. The instruction now appears right before the merge block it belongs with, in the shared update reference and both hand maintained monoliths, with a matching sanctioned diff predicate in gen.py's monolith round trip guard. Co-Authored-By: Claude Sonnet 5 --- tools/skillgen/fragments/core/aider.md | 4 ++-- tools/skillgen/fragments/core/devin.md | 5 +++-- .../fragments/references/shared/update.md | 4 ++-- tools/skillgen/gen.py | 19 +++++++++++++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 0f39a9614a..f6ce396527 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -835,6 +835,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json .graphify_old.json` Then: @@ -890,8 +891,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json .graphify_old.json` -Clean up after: `rm -f .graphify_old.json` +Clean up the backup after: `rm -f .graphify_old.json` --- diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 90dccf4b6a..8649cc3f5d 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -973,6 +973,8 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` + Then: ```bash @@ -1026,8 +1028,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/fragments/references/shared/update.md b/tools/skillgen/fragments/references/shared/update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/fragments/references/shared/update.md +++ b/tools/skillgen/fragments/references/shared/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 22c5125f98..7536724903 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1201,6 +1201,24 @@ def _is_install_failure_gate_fix_line(line: str) -> bool: ) +def _is_update_backup_reorder_fix_line(line: str) -> bool: + """Whether a line is part of the #1619 C4 backup-ordering fix. + + "Before the merge step, save the old graph" appeared AFTER the merge + block and the diff block that consumes the backup, so an agent executing + top to bottom reached it too late and the post-update diff's `if + old_data:` silently no-opped every time. The instruction now appears + before the merge block it belongs with; the trailing cleanup line stays + where it was, reworded to stop implying a backup step just above it. + """ + stripped = line.strip() + return ( + stripped.startswith("Before the merge step") + or stripped.startswith("Clean up after:") + or stripped.startswith("Clean up the backup after:") + ) + + def _is_input_path_slash_guidance_line(line: str) -> bool: """Whether a line is the #1619 B1 forward-slash INPUT_PATH guidance. @@ -1237,6 +1255,7 @@ def _is_input_path_slash_guidance_line(line: str) -> bool: _is_no_cluster_force_fix_line, _is_input_path_slash_guidance_line, _is_install_failure_gate_fix_line, + _is_update_backup_reorder_fix_line, ) From e977600aa25100bee247c2fbc208efd125fcac04 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:55:38 +0530 Subject: [PATCH 14/36] Regenerate skill artifacts for the update backup reorder fix Co-Authored-By: Claude Sonnet 5 --- graphify/skill-aider.md | 4 ++-- graphify/skill-devin.md | 5 +++-- graphify/skills/agents/references/update.md | 4 ++-- graphify/skills/amp/references/update.md | 4 ++-- graphify/skills/claude/references/update.md | 4 ++-- graphify/skills/claw/references/update.md | 4 ++-- graphify/skills/codex/references/update.md | 4 ++-- graphify/skills/copilot/references/update.md | 4 ++-- graphify/skills/droid/references/update.md | 4 ++-- graphify/skills/kilo/references/update.md | 4 ++-- graphify/skills/kiro/references/update.md | 4 ++-- graphify/skills/opencode/references/update.md | 4 ++-- graphify/skills/pi/references/update.md | 4 ++-- graphify/skills/trae/references/update.md | 4 ++-- graphify/skills/vscode/references/update.md | 4 ++-- graphify/skills/windows/references/update.md | 4 ++-- tools/skillgen/expected/graphify__skill-aider.md | 4 ++-- tools/skillgen/expected/graphify__skill-devin.md | 5 +++-- .../expected/graphify__skills__agents__references__update.md | 4 ++-- .../expected/graphify__skills__amp__references__update.md | 4 ++-- .../expected/graphify__skills__claude__references__update.md | 4 ++-- .../expected/graphify__skills__claw__references__update.md | 4 ++-- .../expected/graphify__skills__codex__references__update.md | 4 ++-- .../graphify__skills__copilot__references__update.md | 4 ++-- .../expected/graphify__skills__droid__references__update.md | 4 ++-- .../expected/graphify__skills__kilo__references__update.md | 4 ++-- .../expected/graphify__skills__kiro__references__update.md | 4 ++-- .../graphify__skills__opencode__references__update.md | 4 ++-- .../expected/graphify__skills__pi__references__update.md | 4 ++-- .../expected/graphify__skills__trae__references__update.md | 4 ++-- .../expected/graphify__skills__vscode__references__update.md | 4 ++-- .../graphify__skills__windows__references__update.md | 4 ++-- 32 files changed, 66 insertions(+), 64 deletions(-) diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 0f39a9614a..f6ce396527 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -835,6 +835,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json .graphify_old.json` Then: @@ -890,8 +891,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json .graphify_old.json` -Clean up after: `rm -f .graphify_old.json` +Clean up the backup after: `rm -f .graphify_old.json` --- diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 90dccf4b6a..8649cc3f5d 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -973,6 +973,8 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` + Then: ```bash @@ -1026,8 +1028,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/agents/references/update.md b/graphify/skills/agents/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/agents/references/update.md +++ b/graphify/skills/agents/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/amp/references/update.md b/graphify/skills/amp/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/amp/references/update.md +++ b/graphify/skills/amp/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/claude/references/update.md b/graphify/skills/claude/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/claude/references/update.md +++ b/graphify/skills/claude/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/claw/references/update.md b/graphify/skills/claw/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/claw/references/update.md +++ b/graphify/skills/claw/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/codex/references/update.md b/graphify/skills/codex/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/codex/references/update.md +++ b/graphify/skills/codex/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/copilot/references/update.md b/graphify/skills/copilot/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/copilot/references/update.md +++ b/graphify/skills/copilot/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/droid/references/update.md b/graphify/skills/droid/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/droid/references/update.md +++ b/graphify/skills/droid/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/kilo/references/update.md b/graphify/skills/kilo/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/kilo/references/update.md +++ b/graphify/skills/kilo/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/kiro/references/update.md b/graphify/skills/kiro/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/kiro/references/update.md +++ b/graphify/skills/kiro/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/opencode/references/update.md b/graphify/skills/opencode/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/opencode/references/update.md +++ b/graphify/skills/opencode/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/pi/references/update.md b/graphify/skills/pi/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/pi/references/update.md +++ b/graphify/skills/pi/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/trae/references/update.md b/graphify/skills/trae/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/trae/references/update.md +++ b/graphify/skills/trae/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/vscode/references/update.md b/graphify/skills/vscode/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/vscode/references/update.md +++ b/graphify/skills/vscode/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/windows/references/update.md b/graphify/skills/windows/references/update.md index 3632fd4126..2748bff927 100644 --- a/graphify/skills/windows/references/update.md +++ b/graphify/skills/windows/references/update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 0f39a9614a..f6ce396527 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -835,6 +835,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json .graphify_old.json` Then: @@ -890,8 +891,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json .graphify_old.json` -Clean up after: `rm -f .graphify_old.json` +Clean up the backup after: `rm -f .graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 90dccf4b6a..8649cc3f5d 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -973,6 +973,8 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` + Then: ```bash @@ -1026,8 +1028,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__agents__references__update.md b/tools/skillgen/expected/graphify__skills__agents__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__update.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__amp__references__update.md b/tools/skillgen/expected/graphify__skills__amp__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__update.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__claude__references__update.md b/tools/skillgen/expected/graphify__skills__claude__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__claw__references__update.md b/tools/skillgen/expected/graphify__skills__claw__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__codex__references__update.md b/tools/skillgen/expected/graphify__skills__codex__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__update.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__update.md b/tools/skillgen/expected/graphify__skills__copilot__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__update.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__droid__references__update.md b/tools/skillgen/expected/graphify__skills__droid__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__update.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__update.md b/tools/skillgen/expected/graphify__skills__kilo__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__update.md b/tools/skillgen/expected/graphify__skills__kiro__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__update.md b/tools/skillgen/expected/graphify__skills__opencode__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__pi__references__update.md b/tools/skillgen/expected/graphify__skills__pi__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__update.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__trae__references__update.md b/tools/skillgen/expected/graphify__skills__trae__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__update.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__update.md b/tools/skillgen/expected/graphify__skills__vscode__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__windows__references__update.md b/tools/skillgen/expected/graphify__skills__windows__references__update.md index 3632fd4126..2748bff927 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__update.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__update.md @@ -79,6 +79,7 @@ Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'e fi ``` +Before the merge step below, save the old graph so the post-update diff has something to compare against: `cp graphify-out/graph.json graphify-out/.graphify_old.json` Then: @@ -194,8 +195,7 @@ if old_data: " ``` -Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` +Clean up the backup after: `rm -f graphify-out/.graphify_old.json` --- From 58f10317d8f65150d5d2a710f223787c239fd1fc Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:55:38 +0530 Subject: [PATCH 15/36] Add a regression test for the update backup ordering Asserts the backup instruction precedes both the merge call and the diff block that reads the backup file, across the shared update reference and both monoliths. Co-Authored-By: Claude Sonnet 5 --- tests/test_skillgen.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index 9627f78046..9eb9219562 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -740,6 +740,36 @@ def test_step1_gates_on_a_still_failed_install(): assert gate_i < write_i, f"[{key}] Step 1 gate does not precede the interpreter-path write" +def test_update_backup_instruction_precedes_the_merge_it_backs_up(): + """#1619 C4: "save the old graph" must appear BEFORE the merge block and + the diff block that consumes it. An agent reading top to bottom that + reaches the merge before being told to back up never creates + .graphify_old.json, so the post-update diff's `if old_data:` silently + no-ops on every run instead of ever showing a diff. + """ + _, claude_refs = _platform_artifacts("claude") + update_body = claude_refs["update.md"] + platforms = gen.load_platforms() + bodies = {"claude (references/update.md)": update_body} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + lines = body.splitlines() + backup_i = next( + i for i, l in enumerate(lines) if l.strip().startswith("Before the merge step") + ) + merge_i = next( + i for i, l in enumerate(lines) + if "build_merge(" in l or "G_existing.update(G_new)" in l + ) + diff_i = next(i for i, l in enumerate(lines) if "old_data" in l and "Path(" in l) + assert backup_i < merge_i < diff_i, ( + f"[{key}] backup instruction must precede both the merge and the diff " + f"that reads the backup (backup={backup_i}, merge={merge_i}, diff={diff_i})" + ) + + def test_monoliths_scope_semantic_cache_writes_to_uncached_files(): """#1757: generated monoliths pass the dispatched-file allowlist when replacing semantic cache entries.""" From 27a4294b9095d1cd300c18cae7b3d03c72f06e90 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 02:55:38 +0530 Subject: [PATCH 16/36] Add changelog entry for the update backup reorder fix Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2292472389..270fede5e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu ## 0.9.63 (2026-09-16) +- Fix: the `/graphify` skill's `--update` runbook told the agent to back up the old graph for the post-update diff AFTER the merge step and the diff block that reads the backup, so an agent following the runbook top to bottom never created it before the merge ran and the diff silently no-opped on every single update. The instruction now appears before the merge block it belongs with (#1619, thanks @edtrackai). - Fix: `/graphify` skill Step 1 now stops with an actionable error when the interpreter install still fails after the retry, instead of silently writing a broken interpreter path that every later step then failed against with a cryptic error far removed from the real cause (#1619, thanks @edtrackai). - Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell `Resolve-Path` call that saves the scan root is quoted so a path containing a space survives too (#1619, thanks @edtrackai). - Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label (#1619, thanks @edtrackai). From f154981ab6e93dd6824dcbc738acd3af39f55869 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 06:00:09 +0530 Subject: [PATCH 17/36] Quote the interpreter substitution everywhere it is used The saved interpreter path substitution names the interpreter to run and was spliced in unquoted on every one of its 100+ call sites, unlike the already quoted "$PYTHON" form Step 1 itself uses. An interpreter path containing a space, such as a venv under a user directory with a space in its name, word splits into multiple arguments and fails to exec. Every occurrence across the core fragment, both hand maintained monoliths, and five shared reference fragments is now quoted, plus the prose line describing the substitution pattern. The PowerShell translator's match constant is updated to the quoted form too, since it still recognizes the pattern by exact text. Co-Authored-By: Claude Sonnet 5 --- tools/skillgen/fragments/core/aider.md | 70 +++++++++--------- tools/skillgen/fragments/core/core.md | 24 +++---- tools/skillgen/fragments/core/devin.md | 72 +++++++++---------- .../fragments/references/query/default.md | 16 ++--- .../fragments/references/shared/add-watch.md | 4 +- .../fragments/references/shared/exports.md | 2 +- .../fragments/references/shared/transcribe.md | 2 +- .../fragments/references/shared/update.md | 12 ++-- tools/skillgen/fragments/shell/posix.md | 2 +- tools/skillgen/gen.py | 16 ++++- 10 files changed, 117 insertions(+), 103 deletions(-) diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index f6ce396527..e963583afe 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -109,12 +109,12 @@ mkdir -p graphify-out If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -164,7 +164,7 @@ Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transc **Step 2 - Transcribe:** ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os from pathlib import Path from graphify.transcribe import transcribe_all @@ -203,7 +203,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -237,7 +237,7 @@ Print: `"Semantic extraction: N files (sequential — Aider)"` Before dispatching any subagents, check which files already have cached extraction results: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -298,7 +298,7 @@ If more than half the chunks failed, stop and tell the user. Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -322,7 +322,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -336,7 +336,7 @@ print(f'Cached {saved} files') Merge cached + new results into `.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -369,7 +369,7 @@ Clean up temp files: `rm -f .graphify_cached.json .graphify_uncached.txt .graphi #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -408,7 +408,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -474,7 +474,7 @@ Read `.graphify_analysis.json`. For each community key, look at its node labels Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -521,7 +521,7 @@ Replace INPUT_PATH with the actual path. If `--obsidian` was given: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_obsidian, to_canvas @@ -552,7 +552,7 @@ print(' _COMMUNITY_* - overview notes with cohesion scores and dataview queries Generate the HTML graph (always, unless `--no-viz`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_html @@ -579,7 +579,7 @@ else: **If `--neo4j`** - generate a Cypher file for manual import: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_cypher @@ -594,7 +594,7 @@ print('cypher.txt written - import with: cypher-shell < graphify-out/cypher.txt' **If `--neo4j-push `** - push directly to a running Neo4j instance. Ask the user for credentials if not provided: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster @@ -616,7 +616,7 @@ Replace `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD` with actual values. Default ### Step 7b - SVG export (only if --svg flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_svg @@ -638,7 +638,7 @@ print('graph.svg written - embeds in Obsidian, Notion, GitHub READMEs') ### Step 7c - GraphML export (only if --graphml flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.export import to_graphml @@ -680,7 +680,7 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`: If `total_words` from `.graphify_detect.json` is greater than 5,000, run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.benchmark import run_benchmark, print_benchmark from pathlib import Path @@ -698,7 +698,7 @@ Print the output directly in chat. If `total_words <= 5000`, skip silently - the ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone @@ -781,7 +781,7 @@ The graph is the map. Your job after the pipeline is to be the guide. Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -804,7 +804,7 @@ if new_total > 0: If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -827,7 +827,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -840,7 +840,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_json @@ -867,7 +867,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json @@ -900,7 +900,7 @@ Clean up the backup after: `rm -f .graphify_old.json` Skip Steps 1–3. Load the existing graph from `graphify-out/graph.json` and re-run clustering: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.cluster import cluster, score_all from graphify.analyze import god_nodes, surprising_connections @@ -955,7 +955,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -973,7 +973,7 @@ Load `graphify-out/graph.json`, then: 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -1064,7 +1064,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -1077,7 +1077,7 @@ Find the shortest path between two named concepts in the graph. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1087,7 +1087,7 @@ if not Path('graphify-out/graph.json').exists(): If it fails, stop and tell the user to run `/graphify ` first. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1139,7 +1139,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -1150,7 +1150,7 @@ Give a plain-language explanation of a single node - everything connected to it. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1160,7 +1160,7 @@ if not Path('graphify-out/graph.json').exists(): If it fails, stop and tell the user to run `/graphify ` first. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1205,7 +1205,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` --- @@ -1215,7 +1215,7 @@ $(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index 91125759cc..974197ea2a 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -70,7 +70,7 @@ Only when the path is one or more `https://github.com/...` URLs, or several loca ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -135,7 +135,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -161,7 +161,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -183,7 +183,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -227,7 +227,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -251,7 +251,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -265,7 +265,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -298,7 +298,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -337,7 +337,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -404,7 +404,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -434,7 +434,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -505,7 +505,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 8649cc3f5d..eb0b41218c 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -122,12 +122,12 @@ export PYTHONUTF8=1 If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -177,7 +177,7 @@ Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transc **Step 2 - Transcribe:** ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os from pathlib import Path from graphify.transcribe import transcribe_all @@ -216,7 +216,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -254,7 +254,7 @@ Before dispatching subagents, print a timing estimate: Before dispatching any subagents, check which files already have cached extraction results: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -354,7 +354,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re After each subagent call completes, write its result to `graphify-out/.graphify_chunk_N.json`. **After each subagent call completes, read the real token counts from the subagent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then merge: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path from graphify.semantic_cleanup import load_validated_semantic_fragment, sanitize_semantic_fragment @@ -383,7 +383,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -397,7 +397,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.semantic_cleanup import sanitize_semantic_fragment @@ -432,7 +432,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path from graphify.semantic_cleanup import sanitize_semantic_fragment @@ -473,7 +473,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -539,7 +539,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -586,7 +586,7 @@ Replace INPUT_PATH with the actual path. If `--obsidian` was given: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_obsidian, to_canvas @@ -617,7 +617,7 @@ print(' _COMMUNITY_* - overview notes with cohesion scores and dataview queries Generate the HTML graph (always, unless `--no-viz`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_html @@ -670,7 +670,7 @@ The wiki is an agent-crawlable export — `index.md` plus one article per commun Run this before Step 9 (cleanup) so `graphify-out/.graphify_labels.json` is still available. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.wiki import to_wiki @@ -698,7 +698,7 @@ print(' graphify-out/wiki/index.md -> agent entry point') **If `--neo4j`** - generate a Cypher file for manual import: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_cypher @@ -713,7 +713,7 @@ print('cypher.txt written - import with: cypher-shell < graphify-out/cypher.txt' **If `--neo4j-push `** - push directly to a running Neo4j instance. Ask the user for credentials if not provided: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import push_to_neo4j @@ -734,7 +734,7 @@ Replace `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD` with actual values. Default ### Step 7b - SVG export (only if --svg flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_svg @@ -756,7 +756,7 @@ print('graph.svg written - embeds in Obsidian, Notion, GitHub READMEs') ### Step 7c - GraphML export (only if --graphml flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.export import to_graphml @@ -798,7 +798,7 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`: If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.benchmark import run_benchmark, print_benchmark from pathlib import Path @@ -816,7 +816,7 @@ Print the output directly in chat. If `total_words <= 5000`, skip silently - the ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone @@ -920,7 +920,7 @@ fi Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -943,7 +943,7 @@ if new_total > 0: If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -965,7 +965,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -978,7 +978,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_json @@ -1005,7 +1005,7 @@ Then run Steps 4-8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json @@ -1037,7 +1037,7 @@ Clean up the backup after: `rm -f graphify-out/.graphify_old.json` Skip Steps 1-3. Load the existing graph from `graphify-out/graph.json` and re-run clustering: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.cluster import cluster, score_all from graphify.analyze import god_nodes, surprising_connections @@ -1092,7 +1092,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1110,7 +1110,7 @@ Load `graphify-out/graph.json`, then: 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -1201,7 +1201,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` --- @@ -1212,7 +1212,7 @@ Find the shortest path between two named concepts in the graph. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1221,7 +1221,7 @@ if not Path('graphify-out/graph.json').exists(): ``` ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1273,7 +1273,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names. Then explain the pa After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -1284,7 +1284,7 @@ Give a plain-language explanation of a single node - everything connected to it. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1293,7 +1293,7 @@ if not Path('graphify-out/graph.json').exists(): ``` ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1338,7 +1338,7 @@ Replace `NODE_NAME` with the concept. Then write a 3-5 sentence explanation usin After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` --- @@ -1348,7 +1348,7 @@ $(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path diff --git a/tools/skillgen/fragments/references/query/default.md b/tools/skillgen/fragments/references/query/default.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/fragments/references/query/default.md +++ b/tools/skillgen/fragments/references/query/default.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/fragments/references/shared/add-watch.md b/tools/skillgen/fragments/references/shared/add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/fragments/references/shared/add-watch.md +++ b/tools/skillgen/fragments/references/shared/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/fragments/references/shared/exports.md b/tools/skillgen/fragments/references/shared/exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/fragments/references/shared/exports.md +++ b/tools/skillgen/fragments/references/shared/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/fragments/references/shared/transcribe.md b/tools/skillgen/fragments/references/shared/transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/fragments/references/shared/transcribe.md +++ b/tools/skillgen/fragments/references/shared/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/fragments/references/shared/update.md b/tools/skillgen/fragments/references/shared/update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/fragments/references/shared/update.md +++ b/tools/skillgen/fragments/references/shared/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/fragments/shell/posix.md b/tools/skillgen/fragments/shell/posix.md index 68c5dc094b..0297ca0d18 100644 --- a/tools/skillgen/fragments/shell/posix.md +++ b/tools/skillgen/fragments/shell/posix.md @@ -47,4 +47,4 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 7536724903..952a1d6fb1 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -381,7 +381,7 @@ def _render_frontmatter(platform: Platform) -> str: # untranslated bash to the Windows variant. ``_POWERSHELL_BANNED_TOKENS`` is the # belt-and-braces post-check on the final body. -_PY_INVOKE_POSIX = '$(cat graphify-out/.graphify_python) -c "' +_PY_INVOKE_POSIX = '"$(cat graphify-out/.graphify_python)" -c "' _PY_INVOKE_PS_OPEN = "@'" _PY_INVOKE_PS_CLOSE = "'@ | & (Get-Content graphify-out\\.graphify_python) -" _MKDIR_POSIX = "mkdir -p graphify-out" @@ -1219,6 +1219,19 @@ def _is_update_backup_reorder_fix_line(line: str) -> bool: ) +def _is_quoted_interpreter_cat_fix_line(line: str) -> bool: + """Whether a line is part of the #1619 B5 interpreter-substitution quoting fix. + + `$(cat graphify-out/.graphify_python)` was spliced in unquoted everywhere + it names the interpreter to run, so an interpreter path containing a + space (a venv under `C:\\Users\\First Last\\...`) word-split into + multiple arguments. Every occurrence, and the prose line describing the + substitution, is now quoted, matching the `"$PYTHON"` form Step 1 already + used. Both the old (removed) and new (added) forms match here. + """ + return "$(cat graphify-out/.graphify_python)" in line + + def _is_input_path_slash_guidance_line(line: str) -> bool: """Whether a line is the #1619 B1 forward-slash INPUT_PATH guidance. @@ -1256,6 +1269,7 @@ def _is_input_path_slash_guidance_line(line: str) -> bool: _is_input_path_slash_guidance_line, _is_install_failure_gate_fix_line, _is_update_backup_reorder_fix_line, + _is_quoted_interpreter_cat_fix_line, ) From 58a3eabb9d88eeb65eced78316311b645406e53c Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 06:00:16 +0530 Subject: [PATCH 18/36] Regenerate skill artifacts for the interpreter quoting fix Co-Authored-By: Claude Sonnet 5 --- graphify/skill-agents.md | 26 +++---- graphify/skill-aider.md | 70 +++++++++--------- graphify/skill-amp.md | 26 +++---- graphify/skill-claw.md | 26 +++---- graphify/skill-codex.md | 26 +++---- graphify/skill-copilot.md | 26 +++---- graphify/skill-devin.md | 72 +++++++++---------- graphify/skill-droid.md | 26 +++---- graphify/skill-kilo.md | 26 +++---- graphify/skill-kiro.md | 26 +++---- graphify/skill-opencode.md | 26 +++---- graphify/skill-pi.md | 26 +++---- graphify/skill-trae.md | 26 +++---- graphify/skill-vscode.md | 26 +++---- graphify/skill.md | 26 +++---- .../skills/agents/references/add-watch.md | 4 +- graphify/skills/agents/references/exports.md | 2 +- graphify/skills/agents/references/query.md | 16 ++--- .../skills/agents/references/transcribe.md | 2 +- graphify/skills/agents/references/update.md | 12 ++-- graphify/skills/amp/references/add-watch.md | 4 +- graphify/skills/amp/references/exports.md | 2 +- graphify/skills/amp/references/query.md | 16 ++--- graphify/skills/amp/references/transcribe.md | 2 +- graphify/skills/amp/references/update.md | 12 ++-- .../skills/claude/references/add-watch.md | 4 +- graphify/skills/claude/references/exports.md | 2 +- graphify/skills/claude/references/query.md | 16 ++--- .../skills/claude/references/transcribe.md | 2 +- graphify/skills/claude/references/update.md | 12 ++-- graphify/skills/claw/references/add-watch.md | 4 +- graphify/skills/claw/references/exports.md | 2 +- graphify/skills/claw/references/query.md | 16 ++--- graphify/skills/claw/references/transcribe.md | 2 +- graphify/skills/claw/references/update.md | 12 ++-- graphify/skills/codex/references/add-watch.md | 4 +- graphify/skills/codex/references/exports.md | 2 +- graphify/skills/codex/references/query.md | 16 ++--- .../skills/codex/references/transcribe.md | 2 +- graphify/skills/codex/references/update.md | 12 ++-- .../skills/copilot/references/add-watch.md | 4 +- graphify/skills/copilot/references/exports.md | 2 +- graphify/skills/copilot/references/query.md | 16 ++--- .../skills/copilot/references/transcribe.md | 2 +- graphify/skills/copilot/references/update.md | 12 ++-- graphify/skills/droid/references/add-watch.md | 4 +- graphify/skills/droid/references/exports.md | 2 +- graphify/skills/droid/references/query.md | 16 ++--- .../skills/droid/references/transcribe.md | 2 +- graphify/skills/droid/references/update.md | 12 ++-- graphify/skills/kilo/references/add-watch.md | 4 +- graphify/skills/kilo/references/exports.md | 2 +- graphify/skills/kilo/references/query.md | 16 ++--- graphify/skills/kilo/references/transcribe.md | 2 +- graphify/skills/kilo/references/update.md | 12 ++-- graphify/skills/kiro/references/add-watch.md | 4 +- graphify/skills/kiro/references/exports.md | 2 +- graphify/skills/kiro/references/query.md | 16 ++--- graphify/skills/kiro/references/transcribe.md | 2 +- graphify/skills/kiro/references/update.md | 12 ++-- .../skills/opencode/references/add-watch.md | 4 +- .../skills/opencode/references/exports.md | 2 +- graphify/skills/opencode/references/query.md | 16 ++--- .../skills/opencode/references/transcribe.md | 2 +- graphify/skills/opencode/references/update.md | 12 ++-- graphify/skills/pi/references/add-watch.md | 4 +- graphify/skills/pi/references/exports.md | 2 +- graphify/skills/pi/references/query.md | 16 ++--- graphify/skills/pi/references/transcribe.md | 2 +- graphify/skills/pi/references/update.md | 12 ++-- graphify/skills/trae/references/add-watch.md | 4 +- graphify/skills/trae/references/exports.md | 2 +- graphify/skills/trae/references/query.md | 16 ++--- graphify/skills/trae/references/transcribe.md | 2 +- graphify/skills/trae/references/update.md | 12 ++-- .../skills/vscode/references/add-watch.md | 4 +- graphify/skills/vscode/references/exports.md | 2 +- graphify/skills/vscode/references/query.md | 16 ++--- .../skills/vscode/references/transcribe.md | 2 +- graphify/skills/vscode/references/update.md | 12 ++-- .../skills/windows/references/add-watch.md | 4 +- graphify/skills/windows/references/exports.md | 2 +- graphify/skills/windows/references/query.md | 16 ++--- .../skills/windows/references/transcribe.md | 2 +- graphify/skills/windows/references/update.md | 12 ++-- .../expected/graphify__skill-agents.md | 26 +++---- .../expected/graphify__skill-aider.md | 70 +++++++++--------- .../skillgen/expected/graphify__skill-amp.md | 26 +++---- .../skillgen/expected/graphify__skill-claw.md | 26 +++---- .../expected/graphify__skill-codex.md | 26 +++---- .../expected/graphify__skill-copilot.md | 26 +++---- .../expected/graphify__skill-devin.md | 72 +++++++++---------- .../expected/graphify__skill-droid.md | 26 +++---- .../skillgen/expected/graphify__skill-kilo.md | 26 +++---- .../skillgen/expected/graphify__skill-kiro.md | 26 +++---- .../expected/graphify__skill-opencode.md | 26 +++---- tools/skillgen/expected/graphify__skill-pi.md | 26 +++---- .../skillgen/expected/graphify__skill-trae.md | 26 +++---- .../expected/graphify__skill-vscode.md | 26 +++---- tools/skillgen/expected/graphify__skill.md | 26 +++---- ...__skills__agents__references__add-watch.md | 4 +- ...fy__skills__agents__references__exports.md | 2 +- ...hify__skills__agents__references__query.md | 16 ++--- ..._skills__agents__references__transcribe.md | 2 +- ...ify__skills__agents__references__update.md | 12 ++-- ...ify__skills__amp__references__add-watch.md | 4 +- ...phify__skills__amp__references__exports.md | 2 +- ...raphify__skills__amp__references__query.md | 16 ++--- ...fy__skills__amp__references__transcribe.md | 2 +- ...aphify__skills__amp__references__update.md | 12 ++-- ...__skills__claude__references__add-watch.md | 4 +- ...fy__skills__claude__references__exports.md | 2 +- ...hify__skills__claude__references__query.md | 16 ++--- ..._skills__claude__references__transcribe.md | 2 +- ...ify__skills__claude__references__update.md | 12 ++-- ...fy__skills__claw__references__add-watch.md | 4 +- ...hify__skills__claw__references__exports.md | 2 +- ...aphify__skills__claw__references__query.md | 16 ++--- ...y__skills__claw__references__transcribe.md | 2 +- ...phify__skills__claw__references__update.md | 12 ++-- ...y__skills__codex__references__add-watch.md | 4 +- ...ify__skills__codex__references__exports.md | 2 +- ...phify__skills__codex__references__query.md | 16 ++--- ...__skills__codex__references__transcribe.md | 2 +- ...hify__skills__codex__references__update.md | 12 ++-- ..._skills__copilot__references__add-watch.md | 4 +- ...y__skills__copilot__references__exports.md | 2 +- ...ify__skills__copilot__references__query.md | 16 ++--- ...skills__copilot__references__transcribe.md | 2 +- ...fy__skills__copilot__references__update.md | 12 ++-- ...y__skills__droid__references__add-watch.md | 4 +- ...ify__skills__droid__references__exports.md | 2 +- ...phify__skills__droid__references__query.md | 16 ++--- ...__skills__droid__references__transcribe.md | 2 +- ...hify__skills__droid__references__update.md | 12 ++-- ...fy__skills__kilo__references__add-watch.md | 4 +- ...hify__skills__kilo__references__exports.md | 2 +- ...aphify__skills__kilo__references__query.md | 16 ++--- ...y__skills__kilo__references__transcribe.md | 2 +- ...phify__skills__kilo__references__update.md | 12 ++-- ...fy__skills__kiro__references__add-watch.md | 4 +- ...hify__skills__kiro__references__exports.md | 2 +- ...aphify__skills__kiro__references__query.md | 16 ++--- ...y__skills__kiro__references__transcribe.md | 2 +- ...phify__skills__kiro__references__update.md | 12 ++-- ...skills__opencode__references__add-watch.md | 4 +- ...__skills__opencode__references__exports.md | 2 +- ...fy__skills__opencode__references__query.md | 16 ++--- ...kills__opencode__references__transcribe.md | 2 +- ...y__skills__opencode__references__update.md | 12 ++-- ...hify__skills__pi__references__add-watch.md | 4 +- ...aphify__skills__pi__references__exports.md | 2 +- ...graphify__skills__pi__references__query.md | 16 ++--- ...ify__skills__pi__references__transcribe.md | 2 +- ...raphify__skills__pi__references__update.md | 12 ++-- ...fy__skills__trae__references__add-watch.md | 4 +- ...hify__skills__trae__references__exports.md | 2 +- ...aphify__skills__trae__references__query.md | 16 ++--- ...y__skills__trae__references__transcribe.md | 2 +- ...phify__skills__trae__references__update.md | 12 ++-- ...__skills__vscode__references__add-watch.md | 4 +- ...fy__skills__vscode__references__exports.md | 2 +- ...hify__skills__vscode__references__query.md | 16 ++--- ..._skills__vscode__references__transcribe.md | 2 +- ...ify__skills__vscode__references__update.md | 12 ++-- ..._skills__windows__references__add-watch.md | 4 +- ...y__skills__windows__references__exports.md | 2 +- ...ify__skills__windows__references__query.md | 16 ++--- ...skills__windows__references__transcribe.md | 2 +- ...fy__skills__windows__references__update.md | 12 ++-- 170 files changed, 984 insertions(+), 984 deletions(-) diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index cabbd6184e..965f39d84c 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index f6ce396527..e963583afe 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -109,12 +109,12 @@ mkdir -p graphify-out If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -164,7 +164,7 @@ Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transc **Step 2 - Transcribe:** ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os from pathlib import Path from graphify.transcribe import transcribe_all @@ -203,7 +203,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -237,7 +237,7 @@ Print: `"Semantic extraction: N files (sequential — Aider)"` Before dispatching any subagents, check which files already have cached extraction results: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -298,7 +298,7 @@ If more than half the chunks failed, stop and tell the user. Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -322,7 +322,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -336,7 +336,7 @@ print(f'Cached {saved} files') Merge cached + new results into `.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -369,7 +369,7 @@ Clean up temp files: `rm -f .graphify_cached.json .graphify_uncached.txt .graphi #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -408,7 +408,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -474,7 +474,7 @@ Read `.graphify_analysis.json`. For each community key, look at its node labels Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -521,7 +521,7 @@ Replace INPUT_PATH with the actual path. If `--obsidian` was given: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_obsidian, to_canvas @@ -552,7 +552,7 @@ print(' _COMMUNITY_* - overview notes with cohesion scores and dataview queries Generate the HTML graph (always, unless `--no-viz`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_html @@ -579,7 +579,7 @@ else: **If `--neo4j`** - generate a Cypher file for manual import: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_cypher @@ -594,7 +594,7 @@ print('cypher.txt written - import with: cypher-shell < graphify-out/cypher.txt' **If `--neo4j-push `** - push directly to a running Neo4j instance. Ask the user for credentials if not provided: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster @@ -616,7 +616,7 @@ Replace `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD` with actual values. Default ### Step 7b - SVG export (only if --svg flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_svg @@ -638,7 +638,7 @@ print('graph.svg written - embeds in Obsidian, Notion, GitHub READMEs') ### Step 7c - GraphML export (only if --graphml flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.export import to_graphml @@ -680,7 +680,7 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`: If `total_words` from `.graphify_detect.json` is greater than 5,000, run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.benchmark import run_benchmark, print_benchmark from pathlib import Path @@ -698,7 +698,7 @@ Print the output directly in chat. If `total_words <= 5000`, skip silently - the ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone @@ -781,7 +781,7 @@ The graph is the map. Your job after the pipeline is to be the guide. Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -804,7 +804,7 @@ if new_total > 0: If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -827,7 +827,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -840,7 +840,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_json @@ -867,7 +867,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json @@ -900,7 +900,7 @@ Clean up the backup after: `rm -f .graphify_old.json` Skip Steps 1–3. Load the existing graph from `graphify-out/graph.json` and re-run clustering: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.cluster import cluster, score_all from graphify.analyze import god_nodes, surprising_connections @@ -955,7 +955,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -973,7 +973,7 @@ Load `graphify-out/graph.json`, then: 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -1064,7 +1064,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -1077,7 +1077,7 @@ Find the shortest path between two named concepts in the graph. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1087,7 +1087,7 @@ if not Path('graphify-out/graph.json').exists(): If it fails, stop and tell the user to run `/graphify ` first. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1139,7 +1139,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -1150,7 +1150,7 @@ Give a plain-language explanation of a single node - everything connected to it. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1160,7 +1160,7 @@ if not Path('graphify-out/graph.json').exists(): If it fails, stop and tell the user to run `/graphify ` first. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1205,7 +1205,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` --- @@ -1215,7 +1215,7 @@ $(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index cabbd6184e..965f39d84c 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index de07d94ac5..878aefbbe6 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index 3de8759fac..e8ddb27284 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index de07d94ac5..878aefbbe6 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 8649cc3f5d..eb0b41218c 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -122,12 +122,12 @@ export PYTHONUTF8=1 If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -177,7 +177,7 @@ Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transc **Step 2 - Transcribe:** ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os from pathlib import Path from graphify.transcribe import transcribe_all @@ -216,7 +216,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -254,7 +254,7 @@ Before dispatching subagents, print a timing estimate: Before dispatching any subagents, check which files already have cached extraction results: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -354,7 +354,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re After each subagent call completes, write its result to `graphify-out/.graphify_chunk_N.json`. **After each subagent call completes, read the real token counts from the subagent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then merge: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path from graphify.semantic_cleanup import load_validated_semantic_fragment, sanitize_semantic_fragment @@ -383,7 +383,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -397,7 +397,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.semantic_cleanup import sanitize_semantic_fragment @@ -432,7 +432,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path from graphify.semantic_cleanup import sanitize_semantic_fragment @@ -473,7 +473,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -539,7 +539,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -586,7 +586,7 @@ Replace INPUT_PATH with the actual path. If `--obsidian` was given: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_obsidian, to_canvas @@ -617,7 +617,7 @@ print(' _COMMUNITY_* - overview notes with cohesion scores and dataview queries Generate the HTML graph (always, unless `--no-viz`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_html @@ -670,7 +670,7 @@ The wiki is an agent-crawlable export — `index.md` plus one article per commun Run this before Step 9 (cleanup) so `graphify-out/.graphify_labels.json` is still available. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.wiki import to_wiki @@ -698,7 +698,7 @@ print(' graphify-out/wiki/index.md -> agent entry point') **If `--neo4j`** - generate a Cypher file for manual import: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_cypher @@ -713,7 +713,7 @@ print('cypher.txt written - import with: cypher-shell < graphify-out/cypher.txt' **If `--neo4j-push `** - push directly to a running Neo4j instance. Ask the user for credentials if not provided: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import push_to_neo4j @@ -734,7 +734,7 @@ Replace `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD` with actual values. Default ### Step 7b - SVG export (only if --svg flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_svg @@ -756,7 +756,7 @@ print('graph.svg written - embeds in Obsidian, Notion, GitHub READMEs') ### Step 7c - GraphML export (only if --graphml flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.export import to_graphml @@ -798,7 +798,7 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`: If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.benchmark import run_benchmark, print_benchmark from pathlib import Path @@ -816,7 +816,7 @@ Print the output directly in chat. If `total_words <= 5000`, skip silently - the ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone @@ -920,7 +920,7 @@ fi Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -943,7 +943,7 @@ if new_total > 0: If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -965,7 +965,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -978,7 +978,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_json @@ -1005,7 +1005,7 @@ Then run Steps 4-8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json @@ -1037,7 +1037,7 @@ Clean up the backup after: `rm -f graphify-out/.graphify_old.json` Skip Steps 1-3. Load the existing graph from `graphify-out/graph.json` and re-run clustering: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.cluster import cluster, score_all from graphify.analyze import god_nodes, surprising_connections @@ -1092,7 +1092,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1110,7 +1110,7 @@ Load `graphify-out/graph.json`, then: 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -1201,7 +1201,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` --- @@ -1212,7 +1212,7 @@ Find the shortest path between two named concepts in the graph. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1221,7 +1221,7 @@ if not Path('graphify-out/graph.json').exists(): ``` ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1273,7 +1273,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names. Then explain the pa After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -1284,7 +1284,7 @@ Give a plain-language explanation of a single node - everything connected to it. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1293,7 +1293,7 @@ if not Path('graphify-out/graph.json').exists(): ``` ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1338,7 +1338,7 @@ Replace `NODE_NAME` with the concept. Then write a 3-5 sentence explanation usin After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` --- @@ -1348,7 +1348,7 @@ $(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index 2fb4dfbd80..eb209b3907 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index f445e67673..180ffa3be4 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index de07d94ac5..878aefbbe6 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index ee0aca0b06..cdefca678b 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -295,7 +295,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -319,7 +319,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -333,7 +333,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -366,7 +366,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -405,7 +405,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -472,7 +472,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -502,7 +502,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -573,7 +573,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index de07d94ac5..878aefbbe6 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index afca54235e..239ed662df 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -301,7 +301,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -325,7 +325,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -339,7 +339,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -372,7 +372,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -411,7 +411,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -478,7 +478,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -508,7 +508,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -579,7 +579,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 089116e47d..312cf2f8c4 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -299,7 +299,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -323,7 +323,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -337,7 +337,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -370,7 +370,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -409,7 +409,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -476,7 +476,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -506,7 +506,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -577,7 +577,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skill.md b/graphify/skill.md index de07d94ac5..878aefbbe6 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/graphify/skills/agents/references/add-watch.md b/graphify/skills/agents/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/agents/references/add-watch.md +++ b/graphify/skills/agents/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/agents/references/exports.md b/graphify/skills/agents/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/agents/references/exports.md +++ b/graphify/skills/agents/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/agents/references/query.md b/graphify/skills/agents/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/agents/references/query.md +++ b/graphify/skills/agents/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/agents/references/transcribe.md b/graphify/skills/agents/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/agents/references/transcribe.md +++ b/graphify/skills/agents/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/agents/references/update.md b/graphify/skills/agents/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/agents/references/update.md +++ b/graphify/skills/agents/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/amp/references/add-watch.md b/graphify/skills/amp/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/amp/references/add-watch.md +++ b/graphify/skills/amp/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/amp/references/exports.md b/graphify/skills/amp/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/amp/references/exports.md +++ b/graphify/skills/amp/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/amp/references/query.md b/graphify/skills/amp/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/amp/references/query.md +++ b/graphify/skills/amp/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/amp/references/transcribe.md b/graphify/skills/amp/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/amp/references/transcribe.md +++ b/graphify/skills/amp/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/amp/references/update.md b/graphify/skills/amp/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/amp/references/update.md +++ b/graphify/skills/amp/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/claude/references/add-watch.md b/graphify/skills/claude/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/claude/references/add-watch.md +++ b/graphify/skills/claude/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/claude/references/exports.md b/graphify/skills/claude/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/claude/references/exports.md +++ b/graphify/skills/claude/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/claude/references/query.md b/graphify/skills/claude/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/claude/references/query.md +++ b/graphify/skills/claude/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/claude/references/transcribe.md b/graphify/skills/claude/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/claude/references/transcribe.md +++ b/graphify/skills/claude/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/claude/references/update.md b/graphify/skills/claude/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/claude/references/update.md +++ b/graphify/skills/claude/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/claw/references/add-watch.md b/graphify/skills/claw/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/claw/references/add-watch.md +++ b/graphify/skills/claw/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/claw/references/exports.md b/graphify/skills/claw/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/claw/references/exports.md +++ b/graphify/skills/claw/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/claw/references/query.md b/graphify/skills/claw/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/claw/references/query.md +++ b/graphify/skills/claw/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/claw/references/transcribe.md b/graphify/skills/claw/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/claw/references/transcribe.md +++ b/graphify/skills/claw/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/claw/references/update.md b/graphify/skills/claw/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/claw/references/update.md +++ b/graphify/skills/claw/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/codex/references/add-watch.md b/graphify/skills/codex/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/codex/references/add-watch.md +++ b/graphify/skills/codex/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/codex/references/exports.md b/graphify/skills/codex/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/codex/references/exports.md +++ b/graphify/skills/codex/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/codex/references/query.md b/graphify/skills/codex/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/codex/references/query.md +++ b/graphify/skills/codex/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/codex/references/transcribe.md b/graphify/skills/codex/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/codex/references/transcribe.md +++ b/graphify/skills/codex/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/codex/references/update.md b/graphify/skills/codex/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/codex/references/update.md +++ b/graphify/skills/codex/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/copilot/references/add-watch.md b/graphify/skills/copilot/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/copilot/references/add-watch.md +++ b/graphify/skills/copilot/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/copilot/references/exports.md b/graphify/skills/copilot/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/copilot/references/exports.md +++ b/graphify/skills/copilot/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/copilot/references/query.md b/graphify/skills/copilot/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/copilot/references/query.md +++ b/graphify/skills/copilot/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/copilot/references/transcribe.md b/graphify/skills/copilot/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/copilot/references/transcribe.md +++ b/graphify/skills/copilot/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/copilot/references/update.md b/graphify/skills/copilot/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/copilot/references/update.md +++ b/graphify/skills/copilot/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/droid/references/add-watch.md b/graphify/skills/droid/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/droid/references/add-watch.md +++ b/graphify/skills/droid/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/droid/references/exports.md b/graphify/skills/droid/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/droid/references/exports.md +++ b/graphify/skills/droid/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/droid/references/query.md b/graphify/skills/droid/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/droid/references/query.md +++ b/graphify/skills/droid/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/droid/references/transcribe.md b/graphify/skills/droid/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/droid/references/transcribe.md +++ b/graphify/skills/droid/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/droid/references/update.md b/graphify/skills/droid/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/droid/references/update.md +++ b/graphify/skills/droid/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/kilo/references/add-watch.md b/graphify/skills/kilo/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/kilo/references/add-watch.md +++ b/graphify/skills/kilo/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/kilo/references/exports.md b/graphify/skills/kilo/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/kilo/references/exports.md +++ b/graphify/skills/kilo/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/kilo/references/query.md b/graphify/skills/kilo/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/kilo/references/query.md +++ b/graphify/skills/kilo/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/kilo/references/transcribe.md b/graphify/skills/kilo/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/kilo/references/transcribe.md +++ b/graphify/skills/kilo/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/kilo/references/update.md b/graphify/skills/kilo/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/kilo/references/update.md +++ b/graphify/skills/kilo/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/kiro/references/add-watch.md b/graphify/skills/kiro/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/kiro/references/add-watch.md +++ b/graphify/skills/kiro/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/kiro/references/exports.md b/graphify/skills/kiro/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/kiro/references/exports.md +++ b/graphify/skills/kiro/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/kiro/references/query.md b/graphify/skills/kiro/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/kiro/references/query.md +++ b/graphify/skills/kiro/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/kiro/references/transcribe.md b/graphify/skills/kiro/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/kiro/references/transcribe.md +++ b/graphify/skills/kiro/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/kiro/references/update.md b/graphify/skills/kiro/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/kiro/references/update.md +++ b/graphify/skills/kiro/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/opencode/references/add-watch.md b/graphify/skills/opencode/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/opencode/references/add-watch.md +++ b/graphify/skills/opencode/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/opencode/references/exports.md b/graphify/skills/opencode/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/opencode/references/exports.md +++ b/graphify/skills/opencode/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/opencode/references/query.md b/graphify/skills/opencode/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/opencode/references/query.md +++ b/graphify/skills/opencode/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/opencode/references/transcribe.md b/graphify/skills/opencode/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/opencode/references/transcribe.md +++ b/graphify/skills/opencode/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/opencode/references/update.md b/graphify/skills/opencode/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/opencode/references/update.md +++ b/graphify/skills/opencode/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/pi/references/add-watch.md b/graphify/skills/pi/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/pi/references/add-watch.md +++ b/graphify/skills/pi/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/pi/references/exports.md b/graphify/skills/pi/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/pi/references/exports.md +++ b/graphify/skills/pi/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/pi/references/query.md b/graphify/skills/pi/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/pi/references/query.md +++ b/graphify/skills/pi/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/pi/references/transcribe.md b/graphify/skills/pi/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/pi/references/transcribe.md +++ b/graphify/skills/pi/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/pi/references/update.md b/graphify/skills/pi/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/pi/references/update.md +++ b/graphify/skills/pi/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/trae/references/add-watch.md b/graphify/skills/trae/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/trae/references/add-watch.md +++ b/graphify/skills/trae/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/trae/references/exports.md b/graphify/skills/trae/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/trae/references/exports.md +++ b/graphify/skills/trae/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/trae/references/query.md b/graphify/skills/trae/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/trae/references/query.md +++ b/graphify/skills/trae/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/trae/references/transcribe.md b/graphify/skills/trae/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/trae/references/transcribe.md +++ b/graphify/skills/trae/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/trae/references/update.md b/graphify/skills/trae/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/trae/references/update.md +++ b/graphify/skills/trae/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/vscode/references/add-watch.md b/graphify/skills/vscode/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/vscode/references/add-watch.md +++ b/graphify/skills/vscode/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/vscode/references/exports.md b/graphify/skills/vscode/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/vscode/references/exports.md +++ b/graphify/skills/vscode/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/vscode/references/query.md b/graphify/skills/vscode/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/vscode/references/query.md +++ b/graphify/skills/vscode/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/vscode/references/transcribe.md b/graphify/skills/vscode/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/vscode/references/transcribe.md +++ b/graphify/skills/vscode/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/vscode/references/update.md b/graphify/skills/vscode/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/vscode/references/update.md +++ b/graphify/skills/vscode/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/graphify/skills/windows/references/add-watch.md b/graphify/skills/windows/references/add-watch.md index 77844343e1..937edf327c 100644 --- a/graphify/skills/windows/references/add-watch.md +++ b/graphify/skills/windows/references/add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/graphify/skills/windows/references/exports.md b/graphify/skills/windows/references/exports.md index 242ff868e0..27b031e58c 100644 --- a/graphify/skills/windows/references/exports.md +++ b/graphify/skills/windows/references/exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/graphify/skills/windows/references/query.md b/graphify/skills/windows/references/query.md index 56565eb782..fdc9c68d5f 100644 --- a/graphify/skills/windows/references/query.md +++ b/graphify/skills/windows/references/query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/windows/references/transcribe.md b/graphify/skills/windows/references/transcribe.md index b967f83799..27064bfcdb 100644 --- a/graphify/skills/windows/references/transcribe.md +++ b/graphify/skills/windows/references/transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/graphify/skills/windows/references/update.md b/graphify/skills/windows/references/update.md index 2748bff927..a0ca7dd58a 100644 --- a/graphify/skills/windows/references/update.md +++ b/graphify/skills/windows/references/update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index cabbd6184e..965f39d84c 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index f6ce396527..e963583afe 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -109,12 +109,12 @@ mkdir -p graphify-out If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -164,7 +164,7 @@ Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transc **Step 2 - Transcribe:** ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os from pathlib import Path from graphify.transcribe import transcribe_all @@ -203,7 +203,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -237,7 +237,7 @@ Print: `"Semantic extraction: N files (sequential — Aider)"` Before dispatching any subagents, check which files already have cached extraction results: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -298,7 +298,7 @@ If more than half the chunks failed, stop and tell the user. Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -322,7 +322,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -336,7 +336,7 @@ print(f'Cached {saved} files') Merge cached + new results into `.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -369,7 +369,7 @@ Clean up temp files: `rm -f .graphify_cached.json .graphify_uncached.txt .graphi #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -408,7 +408,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -474,7 +474,7 @@ Read `.graphify_analysis.json`. For each community key, look at its node labels Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -521,7 +521,7 @@ Replace INPUT_PATH with the actual path. If `--obsidian` was given: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_obsidian, to_canvas @@ -552,7 +552,7 @@ print(' _COMMUNITY_* - overview notes with cohesion scores and dataview queries Generate the HTML graph (always, unless `--no-viz`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_html @@ -579,7 +579,7 @@ else: **If `--neo4j`** - generate a Cypher file for manual import: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_cypher @@ -594,7 +594,7 @@ print('cypher.txt written - import with: cypher-shell < graphify-out/cypher.txt' **If `--neo4j-push `** - push directly to a running Neo4j instance. Ask the user for credentials if not provided: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster @@ -616,7 +616,7 @@ Replace `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD` with actual values. Default ### Step 7b - SVG export (only if --svg flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_svg @@ -638,7 +638,7 @@ print('graph.svg written - embeds in Obsidian, Notion, GitHub READMEs') ### Step 7c - GraphML export (only if --graphml flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.export import to_graphml @@ -680,7 +680,7 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`: If `total_words` from `.graphify_detect.json` is greater than 5,000, run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.benchmark import run_benchmark, print_benchmark from pathlib import Path @@ -698,7 +698,7 @@ Print the output directly in chat. If `total_words <= 5000`, skip silently - the ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone @@ -781,7 +781,7 @@ The graph is the map. Your job after the pipeline is to be the guide. Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -804,7 +804,7 @@ if new_total > 0: If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -827,7 +827,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -840,7 +840,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_json @@ -867,7 +867,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json @@ -900,7 +900,7 @@ Clean up the backup after: `rm -f .graphify_old.json` Skip Steps 1–3. Load the existing graph from `graphify-out/graph.json` and re-run clustering: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.cluster import cluster, score_all from graphify.analyze import god_nodes, surprising_connections @@ -955,7 +955,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -973,7 +973,7 @@ Load `graphify-out/graph.json`, then: 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -1064,7 +1064,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -1077,7 +1077,7 @@ Find the shortest path between two named concepts in the graph. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1087,7 +1087,7 @@ if not Path('graphify-out/graph.json').exists(): If it fails, stop and tell the user to run `/graphify ` first. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1139,7 +1139,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -1150,7 +1150,7 @@ Give a plain-language explanation of a single node - everything connected to it. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1160,7 +1160,7 @@ if not Path('graphify-out/graph.json').exists(): If it fails, stop and tell the user to run `/graphify ` first. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1205,7 +1205,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` --- @@ -1215,7 +1215,7 @@ $(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index cabbd6184e..965f39d84c 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index de07d94ac5..878aefbbe6 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index 3de8759fac..e8ddb27284 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index de07d94ac5..878aefbbe6 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 8649cc3f5d..eb0b41218c 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -122,12 +122,12 @@ export PYTHONUTF8=1 If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -177,7 +177,7 @@ Set it as `GRAPHIFY_WHISPER_PROMPT` in the environment before running the transc **Step 2 - Transcribe:** ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os from pathlib import Path from graphify.transcribe import transcribe_all @@ -216,7 +216,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -254,7 +254,7 @@ Before dispatching subagents, print a timing estimate: Before dispatching any subagents, check which files already have cached extraction results: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -354,7 +354,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re After each subagent call completes, write its result to `graphify-out/.graphify_chunk_N.json`. **After each subagent call completes, read the real token counts from the subagent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then merge: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path from graphify.semantic_cleanup import load_validated_semantic_fragment, sanitize_semantic_fragment @@ -383,7 +383,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -397,7 +397,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.semantic_cleanup import sanitize_semantic_fragment @@ -432,7 +432,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path from graphify.semantic_cleanup import sanitize_semantic_fragment @@ -473,7 +473,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -539,7 +539,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -586,7 +586,7 @@ Replace INPUT_PATH with the actual path. If `--obsidian` was given: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_obsidian, to_canvas @@ -617,7 +617,7 @@ print(' _COMMUNITY_* - overview notes with cohesion scores and dataview queries Generate the HTML graph (always, unless `--no-viz`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_html @@ -670,7 +670,7 @@ The wiki is an agent-crawlable export — `index.md` plus one article per commun Run this before Step 9 (cleanup) so `graphify-out/.graphify_labels.json` is still available. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.wiki import to_wiki @@ -698,7 +698,7 @@ print(' graphify-out/wiki/index.md -> agent entry point') **If `--neo4j`** - generate a Cypher file for manual import: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_cypher @@ -713,7 +713,7 @@ print('cypher.txt written - import with: cypher-shell < graphify-out/cypher.txt' **If `--neo4j-push `** - push directly to a running Neo4j instance. Ask the user for credentials if not provided: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import push_to_neo4j @@ -734,7 +734,7 @@ Replace `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD` with actual values. Default ### Step 7b - SVG export (only if --svg flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_svg @@ -756,7 +756,7 @@ print('graph.svg written - embeds in Obsidian, Notion, GitHub READMEs') ### Step 7c - GraphML export (only if --graphml flag) ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.build import build_from_json from graphify.export import to_graphml @@ -798,7 +798,7 @@ To configure in Claude Desktop, add to `claude_desktop_config.json`: If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.benchmark import run_benchmark, print_benchmark from pathlib import Path @@ -816,7 +816,7 @@ Print the output directly in chat. If `total_words <= 5000`, skip silently - the ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone @@ -920,7 +920,7 @@ fi Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -943,7 +943,7 @@ if new_total > 0: If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -965,7 +965,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -978,7 +978,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.export import to_json @@ -1005,7 +1005,7 @@ Then run Steps 4-8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json @@ -1037,7 +1037,7 @@ Clean up the backup after: `rm -f graphify-out/.graphify_old.json` Skip Steps 1-3. Load the existing graph from `graphify-out/graph.json` and re-run clustering: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.cluster import cluster, score_all from graphify.analyze import god_nodes, surprising_connections @@ -1092,7 +1092,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1110,7 +1110,7 @@ Load `graphify-out/graph.json`, then: 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -1201,7 +1201,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` --- @@ -1212,7 +1212,7 @@ Find the shortest path between two named concepts in the graph. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1221,7 +1221,7 @@ if not Path('graphify-out/graph.json').exists(): ``` ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1273,7 +1273,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names. Then explain the pa After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -1284,7 +1284,7 @@ Give a plain-language explanation of a single node - everything connected to it. First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -1293,7 +1293,7 @@ if not Path('graphify-out/graph.json').exists(): ``` ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -1338,7 +1338,7 @@ Replace `NODE_NAME` with the concept. Then write a 3-5 sentence explanation usin After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` --- @@ -1348,7 +1348,7 @@ $(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index 2fb4dfbd80..eb209b3907 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -300,7 +300,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -324,7 +324,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -338,7 +338,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -371,7 +371,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -410,7 +410,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -477,7 +477,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -507,7 +507,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -578,7 +578,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index f445e67673..180ffa3be4 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index de07d94ac5..878aefbbe6 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index ee0aca0b06..cdefca678b 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -295,7 +295,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -319,7 +319,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -333,7 +333,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -366,7 +366,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -405,7 +405,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -472,7 +472,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -502,7 +502,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -573,7 +573,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index de07d94ac5..878aefbbe6 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index afca54235e..239ed662df 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -301,7 +301,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -325,7 +325,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -339,7 +339,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -372,7 +372,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -411,7 +411,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -478,7 +478,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -508,7 +508,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -579,7 +579,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 089116e47d..312cf2f8c4 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -299,7 +299,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -323,7 +323,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -337,7 +337,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -370,7 +370,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -409,7 +409,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -476,7 +476,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -506,7 +506,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -577,7 +577,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index de07d94ac5..878aefbbe6 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -117,12 +117,12 @@ echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root If the import succeeds, print nothing and move straight to Step 2. If it prints the ERROR above, stop and tell the user what happened - do not proceed to Step 2. -**In every subsequent bash block, replace `python3` with `$(cat graphify-out/.graphify_python)` to use the correct interpreter.** +**In every subsequent bash block, replace `python3` with `"$(cat graphify-out/.graphify_python)"` to use the correct interpreter.** ### Step 2 - Detect files ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.detect import detect from pathlib import Path @@ -187,7 +187,7 @@ Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is determin For any code files detected, run AST extraction in parallel with Part B subagents: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.extract import collect_files, extract from pathlib import Path @@ -213,7 +213,7 @@ else: **Fast path:** If detection found zero docs, papers, and images (code-only corpus), skip Part B entirely and go straight to Part C. AST handles code - there is nothing for semantic subagents to do. **First write an empty semantic file** so Part C's merge has its input (it reads `.graphify_semantic.json` unconditionally; without this a code-only run hits `FileNotFoundError`): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -235,7 +235,7 @@ Before dispatching any subagents, check which files already have cached extracti SPEC_PATH below is the **absolute** path of the `references/extraction-spec.md` that ships beside this SKILL.md — the same file Step B2 loads and hands to every subagent. It is the extraction prompt, so cache entries are attributed to it: when a graphify upgrade changes the prompt, entries produced by the old one are re-extracted instead of replayed, and unchanged prompts keep their entries (#1939). Substitute the real path in both Step B0 and Step B3 — pass the same one to each, and do not drop the argument. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import check_semantic_cache from pathlib import Path @@ -303,7 +303,7 @@ If more than half the chunks failed or are missing, stop and tell the user to re Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, glob from pathlib import Path @@ -327,7 +327,7 @@ print(f'Merged {len(chunks)} chunks: {total_in:,} in / {total_out:,} out tokens' Save new results to cache. Pass the same SPEC_PATH as Step B0 — it stamps each entry with the prompt that produced it, and a write under a different prompt than the read lands where the next run won't look (#1939): ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.cache import save_semantic_cache from pathlib import Path @@ -341,7 +341,7 @@ print(f'Cached {saved} files') Merge cached + new results into `graphify-out/.graphify_semantic.json`: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -374,7 +374,7 @@ Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.gra #### Part C - Merge AST + semantic into final extraction ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from pathlib import Path @@ -413,7 +413,7 @@ Two more substitutions, in this step's block and Step 5's: replace `IS_NO_CLUSTE ```bash mkdir -p graphify-out -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import cluster, score_all @@ -480,7 +480,7 @@ Replace INPUT_PATH with the actual path. A non-destructive diagnostic on the extraction, before labeling. It surfaces edge collapse, dangling/missing endpoints, and self-loops — the silent-corruption modes of incremental updates and AST/LLM id mismatches. Read-only; never aborts. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.diagnostics import diagnose_extraction, format_diagnostic_report @@ -510,7 +510,7 @@ Read `graphify-out/.graphify_analysis.json`. For each community key, look at its Then regenerate the report and save the labels for the visualizer: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.build import build_from_json from graphify.cluster import score_all @@ -581,7 +581,7 @@ These run only when their flag is present (`--wiki`, `--neo4j`/`--neo4j-push`, ` ### Step 9 - Save manifest, update cost tracker, clean up, and report ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from datetime import datetime, timezone diff --git a/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md b/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__agents__references__exports.md b/tools/skillgen/expected/graphify__skills__agents__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__agents__references__query.md b/tools/skillgen/expected/graphify__skills__agents__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__query.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__agents__references__transcribe.md b/tools/skillgen/expected/graphify__skills__agents__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__agents__references__update.md b/tools/skillgen/expected/graphify__skills__agents__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__update.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md b/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__amp__references__exports.md b/tools/skillgen/expected/graphify__skills__amp__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__amp__references__query.md b/tools/skillgen/expected/graphify__skills__amp__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__query.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__amp__references__transcribe.md b/tools/skillgen/expected/graphify__skills__amp__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__amp__references__update.md b/tools/skillgen/expected/graphify__skills__amp__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__update.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md b/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__claude__references__exports.md b/tools/skillgen/expected/graphify__skills__claude__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__claude__references__query.md b/tools/skillgen/expected/graphify__skills__claude__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__query.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__claude__references__transcribe.md b/tools/skillgen/expected/graphify__skills__claude__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__claude__references__update.md b/tools/skillgen/expected/graphify__skills__claude__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md b/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__claw__references__exports.md b/tools/skillgen/expected/graphify__skills__claw__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__claw__references__query.md b/tools/skillgen/expected/graphify__skills__claw__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__query.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__claw__references__transcribe.md b/tools/skillgen/expected/graphify__skills__claw__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__claw__references__update.md b/tools/skillgen/expected/graphify__skills__claw__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md b/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__codex__references__exports.md b/tools/skillgen/expected/graphify__skills__codex__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__codex__references__query.md b/tools/skillgen/expected/graphify__skills__codex__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__query.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__codex__references__transcribe.md b/tools/skillgen/expected/graphify__skills__codex__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__codex__references__update.md b/tools/skillgen/expected/graphify__skills__codex__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__update.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md b/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__exports.md b/tools/skillgen/expected/graphify__skills__copilot__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__query.md b/tools/skillgen/expected/graphify__skills__copilot__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__query.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__transcribe.md b/tools/skillgen/expected/graphify__skills__copilot__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__update.md b/tools/skillgen/expected/graphify__skills__copilot__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__update.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md b/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__droid__references__exports.md b/tools/skillgen/expected/graphify__skills__droid__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__droid__references__query.md b/tools/skillgen/expected/graphify__skills__droid__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__query.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__droid__references__transcribe.md b/tools/skillgen/expected/graphify__skills__droid__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__droid__references__update.md b/tools/skillgen/expected/graphify__skills__droid__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__update.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md b/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__exports.md b/tools/skillgen/expected/graphify__skills__kilo__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__query.md b/tools/skillgen/expected/graphify__skills__kilo__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__query.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__transcribe.md b/tools/skillgen/expected/graphify__skills__kilo__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__update.md b/tools/skillgen/expected/graphify__skills__kilo__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md b/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__exports.md b/tools/skillgen/expected/graphify__skills__kiro__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__query.md b/tools/skillgen/expected/graphify__skills__kiro__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__query.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__transcribe.md b/tools/skillgen/expected/graphify__skills__kiro__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__update.md b/tools/skillgen/expected/graphify__skills__kiro__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md b/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__exports.md b/tools/skillgen/expected/graphify__skills__opencode__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__query.md b/tools/skillgen/expected/graphify__skills__opencode__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__query.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__transcribe.md b/tools/skillgen/expected/graphify__skills__opencode__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__update.md b/tools/skillgen/expected/graphify__skills__opencode__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md b/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__pi__references__exports.md b/tools/skillgen/expected/graphify__skills__pi__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__pi__references__query.md b/tools/skillgen/expected/graphify__skills__pi__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__query.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__pi__references__transcribe.md b/tools/skillgen/expected/graphify__skills__pi__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__pi__references__update.md b/tools/skillgen/expected/graphify__skills__pi__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__update.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md b/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__trae__references__exports.md b/tools/skillgen/expected/graphify__skills__trae__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__trae__references__query.md b/tools/skillgen/expected/graphify__skills__trae__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__query.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__trae__references__transcribe.md b/tools/skillgen/expected/graphify__skills__trae__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__trae__references__update.md b/tools/skillgen/expected/graphify__skills__trae__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__update.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md b/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__exports.md b/tools/skillgen/expected/graphify__skills__vscode__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__query.md b/tools/skillgen/expected/graphify__skills__vscode__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__query.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__transcribe.md b/tools/skillgen/expected/graphify__skills__vscode__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__update.md b/tools/skillgen/expected/graphify__skills__vscode__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json diff --git a/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md b/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md index 77844343e1..937edf327c 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md @@ -7,7 +7,7 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path @@ -41,7 +41,7 @@ Supported URL types (auto-detected): Start a background watcher that monitors a folder and auto-updates the graph when files change. ```bash -$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3 +"$(cat graphify-out/.graphify_python)" -m graphify.watch INPUT_PATH --debounce 3 ``` Replace INPUT_PATH with the folder to watch. Behavior depends on what changed: diff --git a/tools/skillgen/expected/graphify__skills__windows__references__exports.md b/tools/skillgen/expected/graphify__skills__windows__references__exports.md index 242ff868e0..27b031e58c 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__exports.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__exports.md @@ -59,7 +59,7 @@ graphify export graphml ### Step 7d - MCP server (only if --mcp flag) ```bash -$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json +"$(cat graphify-out/.graphify_python)" -m graphify.serve graphify-out/graph.json ``` This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live. diff --git a/tools/skillgen/expected/graphify__skills__windows__references__query.md b/tools/skillgen/expected/graphify__skills__windows__references__query.md index 56565eb782..fdc9c68d5f 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__query.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__query.md @@ -11,7 +11,7 @@ Two traversal modes - choose based on the question: First check the graph exists: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " from pathlib import Path if not Path('graphify-out/graph.json').exists(): print('ERROR: No graph found. Run /graphify first to build the graph.') @@ -28,7 +28,7 @@ Fix this **without inventing tokens** by expanding the query against the actual 1. Extract the token vocabulary from node labels: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, re from pathlib import Path data = json.loads(Path('graphify-out/graph.json').read_text(encoding='utf-8')) @@ -77,7 +77,7 @@ If the CLI is unavailable, load `graphify-out/graph.json` and run the traversal 5. If the graph lacks enough information, say so - do not hallucinate edges. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from networkx.readwrite import json_graph import networkx as nx @@ -168,7 +168,7 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -194,7 +194,7 @@ graphify path "NODE_A" "NODE_B" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -246,7 +246,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B ``` --- @@ -262,7 +262,7 @@ graphify explain "NODE_NAME" If the CLI is unavailable, run it inline: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, sys import networkx as nx from networkx.readwrite import json_graph @@ -307,5 +307,5 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__windows__references__transcribe.md b/tools/skillgen/expected/graphify__skills__windows__references__transcribe.md index b967f83799..27064bfcdb 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__transcribe.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__transcribe.md @@ -26,7 +26,7 @@ Read the top god node labels from detect output or analysis, then compose a shor ```bash export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="" -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all diff --git a/tools/skillgen/expected/graphify__skills__windows__references__update.md b/tools/skillgen/expected/graphify__skills__windows__references__update.md index 2748bff927..a0ca7dd58a 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__update.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__update.md @@ -7,7 +7,7 @@ Load this only when the user passed `--update` or `--cluster-only`. A first-time Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time. ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import sys, json from graphify.detect import detect_incremental, save_manifest from pathlib import Path @@ -30,7 +30,7 @@ if new_total > 0: Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\")) @@ -48,7 +48,7 @@ Path('graphify-out/.graphify_detect.json').write_text(json.dumps({ If new files exist, first check whether all changed files are code files: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path @@ -71,7 +71,7 @@ If no new files exist (only deletions), create an empty extraction so the merge ```bash if [ ! -f graphify-out/.graphify_extract.json ]; then echo '[graphify update] Only deletions -- creating empty extraction for merge.' - $(cat graphify-out/.graphify_python) -c " + "$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8') @@ -84,7 +84,7 @@ Before the merge step below, save the old graph so the post-update diff has some Then: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from pathlib import Path from graphify.build import build_merge @@ -171,7 +171,7 @@ Then run Steps 4–8 on the merged graph as normal. After Step 4, show the graph diff: ```bash -$(cat graphify-out/.graphify_python) -c " +"$(cat graphify-out/.graphify_python)" -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json From 453c4d39f0563e22af3a62a54567427051217b88 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 06:00:16 +0530 Subject: [PATCH 19/36] Add a regression test for the interpreter quoting fix Asserts every host that references the interpreter substitution uses only the quoted form, with no unquoted survivor anywhere in its rendered output. Co-Authored-By: Claude Sonnet 5 --- tests/test_skillgen.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index 9eb9219562..ec8ed5a582 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -770,6 +770,36 @@ def test_update_backup_instruction_precedes_the_merge_it_backs_up(): ) +def test_interpreter_cat_substitution_is_quoted_everywhere(): + """#1619 B5: `$(cat graphify-out/.graphify_python)` names the interpreter to + run and must be quoted, like the `"$PYTHON"` form Step 1 already uses -- + an unquoted interpreter path containing a space (a venv under + `C:\\Users\\First Last\\...`) would otherwise word-split into multiple + arguments and fail to exec. + """ + claude_core, claude_refs = _platform_artifacts("claude") + platforms = gen.load_platforms() + bodies = {"claude": claude_core, **{f"claude:{k}": v for k, v in claude_refs.items()}} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + found_any = False + for key, body in bodies.items(): + if "$(cat graphify-out/.graphify_python)" not in body: + continue + found_any = True + assert '"$(cat graphify-out/.graphify_python)"' in body, ( + f"[{key}] has the interpreter substitution but not the quoted form" + ) + # every occurrence must be the quoted form -- an unquoted survivor would + # still contain the bare substring outside any quoted instance. + unquoted = body.replace('"$(cat graphify-out/.graphify_python)"', "") + assert "$(cat graphify-out/.graphify_python)" not in unquoted, ( + f"[{key}] an unquoted $(cat ...) interpreter substitution survived" + ) + assert found_any, "no host's rendered output referenced the interpreter substitution at all" + + def test_monoliths_scope_semantic_cache_writes_to_uncached_files(): """#1757: generated monoliths pass the dispatched-file allowlist when replacing semantic cache entries.""" From df17bb96bd06a77cc857d7186a4809bdaef13588 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 06:00:16 +0530 Subject: [PATCH 20/36] Add changelog entry for the interpreter quoting fix Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 270fede5e4..17a4cdd907 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu ## 0.9.63 (2026-09-16) +- Fix: `$(cat graphify-out/.graphify_python)`, the `/graphify` skill's interpreter substitution used at 100+ call sites, was spliced in unquoted everywhere, unlike the already-quoted `"$PYTHON"` form Step 1 itself uses — an interpreter path containing a space (a venv under a user directory with a space in its name) word-split into multiple arguments and failed to exec. Every occurrence is now quoted (#1619, thanks @edtrackai). - Fix: the `/graphify` skill's `--update` runbook told the agent to back up the old graph for the post-update diff AFTER the merge step and the diff block that reads the backup, so an agent following the runbook top to bottom never created it before the merge ran and the diff silently no-opped on every single update. The instruction now appears before the merge block it belongs with (#1619, thanks @edtrackai). - Fix: `/graphify` skill Step 1 now stops with an actionable error when the interpreter install still fails after the retry, instead of silently writing a broken interpreter path that every later step then failed against with a cryptic error far removed from the real cause (#1619, thanks @edtrackai). - Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell `Resolve-Path` call that saves the scan root is quoted so a path containing a space survives too (#1619, thanks @edtrackai). From 9569a9c0dc96362b99776557163a34f7dc29145d Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 10:07:27 +0530 Subject: [PATCH 21/36] Update the devin skill quoting assertion for the new form test_devin_skill_file_uses_python_c_syntax pinned the pre fix unquoted substring, which the interpreter quoting fix legitimately changed. Updated to assert the quoted form instead. Co-Authored-By: Claude Sonnet 5 --- tests/test_devin.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_devin.py b/tests/test_devin.py index a3bca5d05b..e73e650db2 100644 --- a/tests/test_devin.py +++ b/tests/test_devin.py @@ -240,14 +240,15 @@ def test_devin_skill_file_uses_python_c_syntax(): """Devin skill must use inline python -c syntax (cross-platform, no bash heredocs). All mature graphify skills use the interpreter-detection pattern - ``$(cat graphify-out/.graphify_python) -c "..."`` rather than bare - ``python -c "..."`` so they work in pipx / venv environments. + ``"$(cat graphify-out/.graphify_python)" -c "..."`` rather than bare + ``python -c "..."`` so they work in pipx / venv environments. Quoted (#1619 + B5) so an interpreter path containing a space does not word-split. """ import graphify skill = (Path(graphify.__file__).parent / "skill-devin.md").read_text() - assert '.graphify_python) -c "' in skill, ( + assert '.graphify_python)" -c "' in skill, ( "skill-devin.md must use the interpreter-detection pattern " - "'$(cat graphify-out/.graphify_python) -c \"...\"'" + "'\"$(cat graphify-out/.graphify_python)\" -c \"...\"'" ) assert "#!/bin/bash" not in skill From e71b792496029388a77660aea3326d0d8ff687d2 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 21:53:25 +0530 Subject: [PATCH 22/36] Pass community_labels through the no cluster Step 4 write A reviewer found that a build with clustering skipped silently lost every node's community_name. Step 5 is the step that normally supplies real community labels, but it is skipped entirely when clustering was skipped, making Step 4's own write the only one for that path. Step 4 already computes the Full Corpus placeholder label just above this call, but never passed it through to to_json, so no node ended up with a community_name at all. Applied to the shared core fragment and both hand maintained monoliths. Co-Authored-By: Claude Sonnet 5 --- tools/skillgen/fragments/core/aider.md | 6 +++++- tools/skillgen/fragments/core/core.md | 6 +++++- tools/skillgen/fragments/core/devin.md | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index e963583afe..f920ea703d 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -442,7 +442,11 @@ questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely - this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index 974197ea2a..890e2972e1 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -376,7 +376,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index eb0b41218c..a5c1a989af 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -507,7 +507,11 @@ questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely - this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) From 769b2d6cc2e2e2d840958c7bf72fdcf9e35d6bf8 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 21:53:31 +0530 Subject: [PATCH 23/36] Sanction the no cluster label fix comment for the monolith guard The to_json call itself was already covered by the existing #1392 predicate's generic match, but the new explanatory comment lines needed their own sanctioned entry or the round trip check treats them as unexplained drift. Co-Authored-By: Claude Sonnet 5 --- tools/skillgen/gen.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 952a1d6fb1..16683fd92e 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1169,6 +1169,15 @@ def _is_no_cluster_force_fix_line(line: str) -> bool: or stripped == "labels = {cid: 'Community ' + str(cid) for cid in communities}" or "regenerated with real labels in Step 5" in line or "Skip this step entirely if `--no-cluster` was given in Step 4" in line + # A review finding on #1619 pointed out the Step 4 to_json() call + # (sanctioned above via the #1392 predicate's generic "to_json(G, + # communities," match) never received community_labels=labels, so a + # --no-cluster build silently lost every node's community_name -- + # Step 5, which normally supplies it, is skipped for that path. The + # explanatory comment added alongside that fix is sanctioned here. + or "because --no-cluster skips Step 5 entirely" in line + or "the 'Full Corpus' label computed above must reach graph.json" in line + or "now or every node silently loses its community_name" in line ) From 9a6187c7fd841edcb522243d3bdf62ebc4ced827 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 21:53:31 +0530 Subject: [PATCH 24/36] Regenerate skill artifacts for the no cluster label fix Co-Authored-By: Claude Sonnet 5 --- graphify/skill-agents.md | 6 +++++- graphify/skill-aider.md | 6 +++++- graphify/skill-amp.md | 6 +++++- graphify/skill-claw.md | 6 +++++- graphify/skill-codex.md | 6 +++++- graphify/skill-copilot.md | 6 +++++- graphify/skill-devin.md | 6 +++++- graphify/skill-droid.md | 6 +++++- graphify/skill-kilo.md | 6 +++++- graphify/skill-kiro.md | 6 +++++- graphify/skill-opencode.md | 6 +++++- graphify/skill-pi.md | 6 +++++- graphify/skill-trae.md | 6 +++++- graphify/skill-vscode.md | 6 +++++- graphify/skill-windows.md | 6 +++++- graphify/skill.md | 6 +++++- tools/skillgen/expected/graphify__skill-agents.md | 6 +++++- tools/skillgen/expected/graphify__skill-aider.md | 6 +++++- tools/skillgen/expected/graphify__skill-amp.md | 6 +++++- tools/skillgen/expected/graphify__skill-claw.md | 6 +++++- tools/skillgen/expected/graphify__skill-codex.md | 6 +++++- tools/skillgen/expected/graphify__skill-copilot.md | 6 +++++- tools/skillgen/expected/graphify__skill-devin.md | 6 +++++- tools/skillgen/expected/graphify__skill-droid.md | 6 +++++- tools/skillgen/expected/graphify__skill-kilo.md | 6 +++++- tools/skillgen/expected/graphify__skill-kiro.md | 6 +++++- tools/skillgen/expected/graphify__skill-opencode.md | 6 +++++- tools/skillgen/expected/graphify__skill-pi.md | 6 +++++- tools/skillgen/expected/graphify__skill-trae.md | 6 +++++- tools/skillgen/expected/graphify__skill-vscode.md | 6 +++++- tools/skillgen/expected/graphify__skill-windows.md | 6 +++++- tools/skillgen/expected/graphify__skill.md | 6 +++++- 32 files changed, 160 insertions(+), 32 deletions(-) diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 965f39d84c..d5457c16c5 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index e963583afe..f920ea703d 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -442,7 +442,11 @@ questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely - this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 965f39d84c..d5457c16c5 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index 878aefbbe6..2c584f2f60 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index e8ddb27284..d7616138ad 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index 878aefbbe6..2c584f2f60 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index eb0b41218c..a5c1a989af 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -507,7 +507,11 @@ questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely - this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index eb209b3907..7f436de524 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index 180ffa3be4..a517457a83 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index 878aefbbe6..2c584f2f60 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index cdefca678b..6616bb92df 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -444,7 +444,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index 878aefbbe6..2c584f2f60 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 239ed662df..a4f07e8b2a 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -450,7 +450,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 312cf2f8c4..776d9623fb 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -448,7 +448,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index c23f256398..4b3f8a3eb3 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -479,7 +479,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/graphify/skill.md b/graphify/skill.md index 878aefbbe6..2c584f2f60 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 965f39d84c..d5457c16c5 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index e963583afe..f920ea703d 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -442,7 +442,11 @@ questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely - this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 965f39d84c..d5457c16c5 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index 878aefbbe6..2c584f2f60 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index e8ddb27284..d7616138ad 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index 878aefbbe6..2c584f2f60 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index eb0b41218c..a5c1a989af 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -507,7 +507,11 @@ questions = suggest_questions(G, communities, labels) # Persist the graph first and only write the report/analysis if it actually # persisted - to_json refuses to shrink an existing graph.json (#479), and a # report describing a graph we did not write would be a lie (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely - this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (fewer nodes than the existing graph). Run a full rebuild to be safe.') raise SystemExit(1) diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index eb209b3907..7f436de524 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -449,7 +449,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index 180ffa3be4..a517457a83 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index 878aefbbe6..2c584f2f60 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index cdefca678b..6616bb92df 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -444,7 +444,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index 878aefbbe6..2c584f2f60 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 239ed662df..a4f07e8b2a 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -450,7 +450,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 312cf2f8c4..776d9623fb 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -448,7 +448,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index c23f256398..4b3f8a3eb3 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -479,7 +479,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index 878aefbbe6..2c584f2f60 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -452,7 +452,11 @@ questions = suggest_questions(G, communities, labels) # nothing) when the new graph is smaller than the existing graph.json. Only write # GRAPH_REPORT.md + the analysis sidecar when the graph was actually written, so # they never describe a graph that graph.json doesn't contain (#1392). -wrote = to_json(G, communities, 'graphify-out/graph.json', force=IS_FORCE) +# community_labels=labels is passed here too, not just in Step 5's rewrite, +# because --no-cluster skips Step 5 entirely -- this is the only write for +# that path, so the 'Full Corpus' label computed above must reach graph.json +# now or every node silently loses its community_name. +wrote = to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE) if not wrote: print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).') print('If this shrink is intentional (you deleted files), re-run a full build with --force.') From 4f15262cad979e5c13ad34dd9fc8a6fafd057569 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 21:53:31 +0530 Subject: [PATCH 25/36] Add a regression test for the no cluster label fix Counts occurrences of the to_json call shape rather than a bare membership check, since Step 5's identical text alone would make a membership check pass even if Step 4's copy were still missing community_labels. Co-Authored-By: Claude Sonnet 5 --- tests/test_skillgen.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index ec8ed5a582..0d748b40b4 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -685,6 +685,32 @@ def test_no_cluster_and_force_flags_are_wired_through(): ) +def test_no_cluster_step_4_write_carries_the_full_corpus_label(): + """Review finding on #1619: Step 5 (which normally supplies real community + labels) is skipped entirely for --no-cluster, making Step 4's write the + only one -- so it must pass community_labels=labels itself, or every node + in a --no-cluster build silently loses its community_name even though the + 'Full Corpus' label was computed right above it.""" + claude_core, _ = _platform_artifacts("claude") + platforms = gen.load_platforms() + bodies = {"claude": claude_core} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + # Step 4 and Step 5 now both use this exact call shape -- Step 5's + # own occurrence alone would make a bare "in body" check pass even + # if Step 4's copy were still missing community_labels, so this + # counts occurrences the same way the neighboring force=IS_FORCE + # assertion above does. + step4_or_5_write = "to_json(G, communities, 'graphify-out/graph.json', community_labels=labels, force=IS_FORCE)" + assert body.count(step4_or_5_write) >= 2, ( + f"[{key}] expected community_labels=labels on both Step 4 and Step 5 " + "to_json calls -- Step 4's is the only write for --no-cluster, since " + "Step 5 is skipped for that path" + ) + + def test_input_path_forward_slash_guidance_is_present(): """#1619 B1: a Windows INPUT_PATH substitution with backslashes corrupts the Python string literal it's spliced into. Every host must tell the From 96f2d1617bf8d8b603598efa989c2917e20f2ef3 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 21:53:31 +0530 Subject: [PATCH 26/36] Update changelog entry for issue 1619 review finding Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17a4cdd907..014ea897d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu - Fix: the `/graphify` skill's `--update` runbook told the agent to back up the old graph for the post-update diff AFTER the merge step and the diff block that reads the backup, so an agent following the runbook top to bottom never created it before the merge ran and the diff silently no-opped on every single update. The instruction now appears before the merge block it belongs with (#1619, thanks @edtrackai). - Fix: `/graphify` skill Step 1 now stops with an actionable error when the interpreter install still fails after the retry, instead of silently writing a broken interpreter path that every later step then failed against with a cryptic error far removed from the real cause (#1619, thanks @edtrackai). - Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell `Resolve-Path` call that saves the scan root is quoted so a path containing a space survives too (#1619, thanks @edtrackai). -- Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label (#1619, thanks @edtrackai). +- Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label. Step 4's write also now passes through the placeholder "Full Corpus" community label it already computes, since it is the only write for that path and every node was silently ending up with no `community_name` at all without it (#1619, thanks @edtrackai). - Feature: Elixir `alias`/`import`/`require`/`use` targets now resolve onto the module's `defmodule` node across files, so the internal module dependency graph is no longer dropped as dangling. Only top-level modules are indexed (a nested `defmodule`, labeled with its bare inner name, cannot capture an unrelated `use ` from another file), and a same-file reference is left unresolved so it cannot clobber the structural `contains` edge (#3603, thanks @ayushcodes10). - Feature: a Rust `self.method()` call now resolves to a method defined on the same type in another file (the common split-`impl`-block layout), pooling methods across every `impl` of one type and refusing to link when two unrelated types share a bare name (#3602, thanks @ayushcodes10). - Feature: a Ruby member call `obj.foo` on a known-type receiver now resolves to a method `foo` inherited from a superclass, including across files, using the same conservative promotion as the implicit-self resolver — a single owning class, matching method kind, and one unambiguous ancestry chain, or it stays dangling (#3585, thanks @oleksii-tumanov). From 0743c09de475ac10893d0475cd84d16a6dd1e008 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 12:54:58 +0530 Subject: [PATCH 27/36] Update the Resolve Path quoting test for the here string capture The old assertion checked for a quoted but still direct substitution of INPUT_PATH into the scan root save's Resolve Path call, the exact form issue 3642 replaced with a literal here string capture on the upstream side this branch just merged. The direct substitution is gone entirely now, quoted or not, so the test needed a form that reflects what the file actually contains today: the here string assignment feeding a variable reference into Resolve Path, which also subsumes this test's own original space safety concern for free. --- tests/test_skillgen.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index 0d748b40b4..18db71df01 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -714,8 +714,14 @@ def test_no_cluster_step_4_write_carries_the_full_corpus_label(): def test_input_path_forward_slash_guidance_is_present(): """#1619 B1: a Windows INPUT_PATH substitution with backslashes corrupts the Python string literal it's spliced into. Every host must tell the - agent to substitute forward slashes instead, and the PowerShell - Resolve-Path call must be quoted so a path with a space in it survives.""" + agent to substitute forward slashes instead, and the PowerShell scan + root save must not splice INPUT_PATH directly into a Resolve-Path call + at all -- issue #3642 replaced that (a bareword substitution there, even + single-quoted, still lets a stray `;`/`|`/`$(...)` in the path execute + as script code) with a single-quoted here-string capture, which also + subsumes #1619 B1's own space-safety concern: a PowerShell variable + reference is passed as one argument regardless of internal spaces, + unlike a bareword substitution.""" claude_core, _ = _platform_artifacts("claude") windows_core, _ = _platform_artifacts("windows") platforms = gen.load_platforms() @@ -728,8 +734,15 @@ def test_input_path_forward_slash_guidance_is_present(): f"[{key}] missing the forward-slash INPUT_PATH guidance" ) - assert "(Resolve-Path 'INPUT_PATH')" in bodies["windows"], ( - "skill-windows.md's Resolve-Path call must be quoted (#1619 B1)" + assert "$InputPathRaw = @'" in bodies["windows"], ( + "skill-windows.md's scan root save must capture INPUT_PATH through " + "a literal here-string, not a direct substitution (#3642)" + ) + assert "(Resolve-Path $InputPathRaw.Trim())" in bodies["windows"], ( + "the captured here-string must be what Resolve-Path resolves" + ) + assert "(Resolve-Path 'INPUT_PATH')" not in bodies["windows"], ( + "the old quoted-but-still-direct Resolve-Path substitution must not survive" ) assert "(Resolve-Path INPUT_PATH)" not in bodies["windows"], ( "the unquoted Resolve-Path call must not survive" From b86bfa3feeb2645473d8e14056a71dd60df70229 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 12:56:04 +0530 Subject: [PATCH 28/36] Update the changelog wording for the scan root save mechanism The existing entry described the PowerShell scan root save as a quoted direct substitution, the mechanism issue 3642 replaced with a literal here string capture once it shipped. Reworded to describe what the file actually does now rather than leaving a factually stale description in place. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe3bedb24..8628042f18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,7 +69,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu - Fix: `$(cat graphify-out/.graphify_python)`, the `/graphify` skill's interpreter substitution used at 100+ call sites, was spliced in unquoted everywhere, unlike the already-quoted `"$PYTHON"` form Step 1 itself uses — an interpreter path containing a space (a venv under a user directory with a space in its name) word-split into multiple arguments and failed to exec. Every occurrence is now quoted (#1619, thanks @edtrackai). - Fix: the `/graphify` skill's `--update` runbook told the agent to back up the old graph for the post-update diff AFTER the merge step and the diff block that reads the backup, so an agent following the runbook top to bottom never created it before the merge ran and the diff silently no-opped on every single update. The instruction now appears before the merge block it belongs with (#1619, thanks @edtrackai). - Fix: `/graphify` skill Step 1 now stops with an actionable error when the interpreter install still fails after the retry, instead of silently writing a broken interpreter path that every later step then failed against with a cryptic error far removed from the real cause (#1619, thanks @edtrackai). -- Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell `Resolve-Path` call that saves the scan root is quoted so a path containing a space survives too (#1619, thanks @edtrackai). +- Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell scan root save reads the path back out of a single quoted here string it captured INPUT_PATH into (rather than substituting it directly into the Resolve-Path call), which also means a path containing a space survives (#1619, thanks @edtrackai; folded into the #3642 here string fix once that shipped, see 0.9.68 above). - Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label. Step 4's write also now passes through the placeholder "Full Corpus" community label it already computes, since it is the only write for that path and every node was silently ending up with no `community_name` at all without it (#1619, thanks @edtrackai). - Feature: Elixir `alias`/`import`/`require`/`use` targets now resolve onto the module's `defmodule` node across files, so the internal module dependency graph is no longer dropped as dangling. Only top-level modules are indexed (a nested `defmodule`, labeled with its bare inner name, cannot capture an unrelated `use ` from another file), and a same-file reference is left unresolved so it cannot clobber the structural `contains` edge (#3603, thanks @ayushcodes10). - Feature: a Rust `self.method()` call now resolves to a method defined on the same type in another file (the common split-`impl`-block layout), pooling methods across every `impl` of one type and refusing to link when two unrelated types share a bare name (#3602, thanks @ayushcodes10). From f391f1d4fda3090ad1db2b23448a04eb289ce11a Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:29:53 +0530 Subject: [PATCH 29/36] Tell the agent to escape a literal quote in INPUT_PATH Every occurrence of INPUT_PATH is substituted into a Python string literal. The existing guidance already covers a Windows backslash corrupting that literal, but said nothing about a literal single quote in the path itself. A path like a user directory containing an apostrophe closes the string literal early, corrupting or hijacking the code that follows the same way an unescaped backslash does. The guidance now also tells the agent to escape a literal single quote before substituting, right after the existing backslash rule it belongs beside. Fixes review finding on PR 3621. --- graphify/skill-agents.md | 2 +- graphify/skill-aider.md | 2 +- graphify/skill-amp.md | 2 +- graphify/skill-claw.md | 2 +- graphify/skill-codex.md | 2 +- graphify/skill-copilot.md | 2 +- graphify/skill-devin.md | 2 +- graphify/skill-droid.md | 2 +- graphify/skill-kilo.md | 2 +- graphify/skill-kiro.md | 2 +- graphify/skill-opencode.md | 2 +- graphify/skill-pi.md | 2 +- graphify/skill-trae.md | 2 +- graphify/skill-vscode.md | 2 +- graphify/skill-windows.md | 2 +- graphify/skill.md | 2 +- tools/skillgen/expected/graphify__skill-agents.md | 2 +- tools/skillgen/expected/graphify__skill-aider.md | 2 +- tools/skillgen/expected/graphify__skill-amp.md | 2 +- tools/skillgen/expected/graphify__skill-claw.md | 2 +- tools/skillgen/expected/graphify__skill-codex.md | 2 +- tools/skillgen/expected/graphify__skill-copilot.md | 2 +- tools/skillgen/expected/graphify__skill-devin.md | 2 +- tools/skillgen/expected/graphify__skill-droid.md | 2 +- tools/skillgen/expected/graphify__skill-kilo.md | 2 +- tools/skillgen/expected/graphify__skill-kiro.md | 2 +- tools/skillgen/expected/graphify__skill-opencode.md | 2 +- tools/skillgen/expected/graphify__skill-pi.md | 2 +- tools/skillgen/expected/graphify__skill-trae.md | 2 +- tools/skillgen/expected/graphify__skill-vscode.md | 2 +- tools/skillgen/expected/graphify__skill-windows.md | 2 +- tools/skillgen/expected/graphify__skill.md | 2 +- tools/skillgen/fragments/core/aider.md | 2 +- tools/skillgen/fragments/core/core.md | 2 +- tools/skillgen/fragments/core/devin.md | 2 +- 35 files changed, 35 insertions(+), 35 deletions(-) diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 0839a0f6ad..cd8eb888cc 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index f920ea703d..f62f9f1b4f 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 0839a0f6ad..cd8eb888cc 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index e1c85710be..4d174fd499 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index bacb012926..8077ec35fe 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index e1c85710be..4d174fd499 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index a5c1a989af..121f7bf6c9 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -67,7 +67,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. Follow these steps in order. Do not skip steps. diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index 5569ea21c2..825f0c70ec 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index 4ff91c0129..ee72e9e795 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index e1c85710be..4d174fd499 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 7dba41920c..881f926b19 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index e1c85710be..4d174fd499 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 73c5772975..1f03e404f4 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 8c5d479bc3..4220a11e04 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index 5a38d10584..0480c05948 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/graphify/skill.md b/graphify/skill.md index e1c85710be..4d174fd499 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 0839a0f6ad..cd8eb888cc 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index f920ea703d..f62f9f1b4f 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 0839a0f6ad..cd8eb888cc 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index e1c85710be..4d174fd499 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index bacb012926..8077ec35fe 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index e1c85710be..4d174fd499 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index a5c1a989af..121f7bf6c9 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -67,7 +67,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index 5569ea21c2..825f0c70ec 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index 4ff91c0129..ee72e9e795 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index e1c85710be..4d174fd499 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index 7dba41920c..881f926b19 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index e1c85710be..4d174fd499 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 73c5772975..1f03e404f4 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 8c5d479bc3..4220a11e04 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index 5a38d10584..0480c05948 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index e1c85710be..4d174fd499 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index f920ea703d..f62f9f1b4f 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -56,7 +56,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. Follow these steps in order. Do not skip steps. diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index 890e2972e1..5ab358b03b 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -53,7 +53,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) — a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. If the path argument starts with `https://github.com/` or `http://github.com/`, treat it as a GitHub URL - run Step 0 before anything else, then continue with the resolved local path. diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index a5c1a989af..121f7bf6c9 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -67,7 +67,7 @@ If the user invoked `/graphify --help` or `/graphify -h` (with no other argument If no path was given, use `.` (current directory). Do not ask the user for a path. -Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. +Every occurrence of `INPUT_PATH` below is a placeholder substituted with this resolved path, inside a Python string literal. On Windows, substitute it with forward slashes (`C:/Users/me/project`, not `C:\Users\me\project`) - a literal backslash in a Windows path splices a stray escape into the Python source (`\t` becomes a tab, `\U` raises a `SyntaxError`), silently or loudly corrupting every block that uses it. If the path itself contains a literal single quote character (e.g. `/Users/o'brien/project`), escape it as `\'` before substituting too — an unescaped quote closes the string literal early, corrupting or hijacking the code that follows. Follow these steps in order. Do not skip steps. From 943a32550159bf7197112896651bc434ea493bd4 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:29:58 +0530 Subject: [PATCH 30/36] Add a regression test for the quote escaping guidance Covers the review finding directly: every host body must tell the agent to escape a literal single quote in INPUT_PATH before substituting it into a Python string literal. Confirmed against pre fix code by restoring the prior fragment sources directly, the test fails there and passes only with the fix applied. --- tests/test_skillgen.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index 18db71df01..40755d0bc4 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -749,6 +749,25 @@ def test_input_path_forward_slash_guidance_is_present(): ) +def test_input_path_quote_escaping_guidance_is_present(): + """Review finding on PR 3621: INPUT_PATH is substituted into a Python + string literal (e.g. Path('INPUT_PATH')) with no guidance about a + literal single quote in the path itself. A path like + /Users/o'brien/project closes the string literal early, corrupting or + hijacking the code that follows -- the same class of gap the existing + backslash guidance already covers for a different character.""" + claude_core, _ = _platform_artifacts("claude") + platforms = gen.load_platforms() + bodies = {"claude": claude_core} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + assert "escape it as" in body and "\\'" in body, ( + f"[{key}] missing the single quote escaping guidance for INPUT_PATH" + ) + + def test_step1_gates_on_a_still_failed_install(): """#1619 B4: a failed install must stop with an actionable error instead of silently writing a broken interpreter path that fails every later step From 40899c2905bedd1f0cf4f84d8f2c5deaeac1486a Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:32:45 +0530 Subject: [PATCH 31/36] Capture the save result answer through a heredoc, not inline ANSWER, the agent's own free text explanation, was spliced directly into a double quoted answer shell argument. An ordinary quote, backtick, or dollar sign anywhere in a normal technical explanation, not just an adversarial one, breaks or hijacks the command the moment it runs. The save result subcommand already accepts a file alternative for exactly this reason. Every save result call now writes ANSWER into a temp file through a single quoted heredoc first, which performs no shell expansion of its body at all, then passes that file through the existing file option instead of splicing the text inline. Sanctioned the new heredoc lines against the monolith round trip guard, matching how the existing quoted interpreter fix documents its own sanctioned diff right next to this one. Fixes review finding on PR 3621. --- graphify/skill-aider.md | 15 ++++++++++--- graphify/skill-devin.md | 15 ++++++++++--- graphify/skills/agents/references/query.md | 15 ++++++++++--- graphify/skills/amp/references/query.md | 15 ++++++++++--- graphify/skills/claude/references/query.md | 15 ++++++++++--- graphify/skills/claw/references/query.md | 15 ++++++++++--- graphify/skills/codex/references/query.md | 15 ++++++++++--- graphify/skills/copilot/references/query.md | 15 ++++++++++--- graphify/skills/droid/references/query.md | 15 ++++++++++--- graphify/skills/kilo/references/query.md | 15 ++++++++++--- graphify/skills/kiro/references/query.md | 15 ++++++++++--- graphify/skills/opencode/references/query.md | 15 ++++++++++--- graphify/skills/pi/references/query.md | 15 ++++++++++--- graphify/skills/trae/references/query.md | 15 ++++++++++--- graphify/skills/vscode/references/query.md | 15 ++++++++++--- graphify/skills/windows/references/query.md | 15 ++++++++++--- .../expected/graphify__skill-aider.md | 15 ++++++++++--- .../expected/graphify__skill-devin.md | 15 ++++++++++--- ...hify__skills__agents__references__query.md | 15 ++++++++++--- ...raphify__skills__amp__references__query.md | 15 ++++++++++--- ...hify__skills__claude__references__query.md | 15 ++++++++++--- ...aphify__skills__claw__references__query.md | 15 ++++++++++--- ...phify__skills__codex__references__query.md | 15 ++++++++++--- ...ify__skills__copilot__references__query.md | 15 ++++++++++--- ...phify__skills__droid__references__query.md | 15 ++++++++++--- ...aphify__skills__kilo__references__query.md | 15 ++++++++++--- ...aphify__skills__kiro__references__query.md | 15 ++++++++++--- ...fy__skills__opencode__references__query.md | 15 ++++++++++--- ...graphify__skills__pi__references__query.md | 15 ++++++++++--- ...aphify__skills__trae__references__query.md | 15 ++++++++++--- ...hify__skills__vscode__references__query.md | 15 ++++++++++--- ...ify__skills__windows__references__query.md | 15 ++++++++++--- tools/skillgen/fragments/core/aider.md | 15 ++++++++++--- tools/skillgen/fragments/core/devin.md | 15 ++++++++++--- .../fragments/references/query/default.md | 15 ++++++++++--- tools/skillgen/gen.py | 22 +++++++++++++++++++ 36 files changed, 442 insertions(+), 105 deletions(-) diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index f62f9f1b4f..b1b072e5dc 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -1068,7 +1068,10 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -1143,7 +1146,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -1209,7 +1215,10 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` --- diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 121f7bf6c9..52ed18186f 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -1205,7 +1205,10 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` --- @@ -1277,7 +1280,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names. Then explain the pa After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -1342,7 +1348,10 @@ Replace `NODE_NAME` with the concept. Then write a 3-5 sentence explanation usin After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` --- diff --git a/graphify/skills/agents/references/query.md b/graphify/skills/agents/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/agents/references/query.md +++ b/graphify/skills/agents/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/amp/references/query.md b/graphify/skills/amp/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/amp/references/query.md +++ b/graphify/skills/amp/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/claude/references/query.md b/graphify/skills/claude/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/claude/references/query.md +++ b/graphify/skills/claude/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/claw/references/query.md b/graphify/skills/claw/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/claw/references/query.md +++ b/graphify/skills/claw/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/codex/references/query.md b/graphify/skills/codex/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/codex/references/query.md +++ b/graphify/skills/codex/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/copilot/references/query.md b/graphify/skills/copilot/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/copilot/references/query.md +++ b/graphify/skills/copilot/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/droid/references/query.md b/graphify/skills/droid/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/droid/references/query.md +++ b/graphify/skills/droid/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/kilo/references/query.md b/graphify/skills/kilo/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/kilo/references/query.md +++ b/graphify/skills/kilo/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/kiro/references/query.md b/graphify/skills/kiro/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/kiro/references/query.md +++ b/graphify/skills/kiro/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/opencode/references/query.md b/graphify/skills/opencode/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/opencode/references/query.md +++ b/graphify/skills/opencode/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/pi/references/query.md b/graphify/skills/pi/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/pi/references/query.md +++ b/graphify/skills/pi/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/trae/references/query.md b/graphify/skills/trae/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/trae/references/query.md +++ b/graphify/skills/trae/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/vscode/references/query.md b/graphify/skills/vscode/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/vscode/references/query.md +++ b/graphify/skills/vscode/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/graphify/skills/windows/references/query.md b/graphify/skills/windows/references/query.md index fdc9c68d5f..6f7515519e 100644 --- a/graphify/skills/windows/references/query.md +++ b/graphify/skills/windows/references/query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index f62f9f1b4f..b1b072e5dc 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -1068,7 +1068,10 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -1143,7 +1146,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -1209,7 +1215,10 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` --- diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 121f7bf6c9..52ed18186f 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -1205,7 +1205,10 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` --- @@ -1277,7 +1280,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names. Then explain the pa After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -1342,7 +1348,10 @@ Replace `NODE_NAME` with the concept. Then write a 3-5 sentence explanation usin After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` --- diff --git a/tools/skillgen/expected/graphify__skills__agents__references__query.md b/tools/skillgen/expected/graphify__skills__agents__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__query.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__amp__references__query.md b/tools/skillgen/expected/graphify__skills__amp__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__query.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__claude__references__query.md b/tools/skillgen/expected/graphify__skills__claude__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__query.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__claw__references__query.md b/tools/skillgen/expected/graphify__skills__claw__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__query.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__codex__references__query.md b/tools/skillgen/expected/graphify__skills__codex__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__query.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__query.md b/tools/skillgen/expected/graphify__skills__copilot__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__query.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__droid__references__query.md b/tools/skillgen/expected/graphify__skills__droid__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__query.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__query.md b/tools/skillgen/expected/graphify__skills__kilo__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__query.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__query.md b/tools/skillgen/expected/graphify__skills__kiro__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__query.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__query.md b/tools/skillgen/expected/graphify__skills__opencode__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__query.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__pi__references__query.md b/tools/skillgen/expected/graphify__skills__pi__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__query.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__trae__references__query.md b/tools/skillgen/expected/graphify__skills__trae__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__query.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__query.md b/tools/skillgen/expected/graphify__skills__vscode__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__query.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/expected/graphify__skills__windows__references__query.md b/tools/skillgen/expected/graphify__skills__windows__references__query.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__query.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__query.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index f62f9f1b4f..b1b072e5dc 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -1068,7 +1068,10 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -1143,7 +1146,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -1209,7 +1215,10 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` --- diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 121f7bf6c9..52ed18186f 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -1205,7 +1205,10 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`, After writing the answer, save it back into the graph so it improves future queries: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` --- @@ -1277,7 +1280,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names. Then explain the pa After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -1342,7 +1348,10 @@ Replace `NODE_NAME` with the concept. Then write a 3-5 sentence explanation usin After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` --- diff --git a/tools/skillgen/fragments/references/query/default.md b/tools/skillgen/fragments/references/query/default.md index fdc9c68d5f..6f7515519e 100644 --- a/tools/skillgen/fragments/references/query/default.md +++ b/tools/skillgen/fragments/references/query/default.md @@ -168,7 +168,10 @@ Replace `QUESTION` with the **expanded** query string, `MODE` with `bfs` or `dfs After writing the answer, save it back into the graph so it improves future queries. Include the expanded tokens inside the `--answer` text (e.g. `"Expanded from original query via vocab: [tokens]. Then traversed..."`) so the next `--update` extracts the expansion history as a graph node: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2 +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "ORIGINAL_QUESTION" --answer-file graphify-out/.save_result_answer.tmp --type query --nodes NODE1 NODE2 ``` Replace `ORIGINAL_QUESTION` with the user's verbatim question, `ANSWER` with your full answer text (containing the expanded-token trace), `NODE1 NODE2` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph. @@ -246,7 +249,10 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Path from NODE_A to NODE_B" --answer-file graphify-out/.save_result_answer.tmp --type path_query --nodes NODE_A NODE_B ``` --- @@ -307,5 +313,8 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent After writing the explanation, save it back: ```bash -"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME +cat > graphify-out/.save_result_answer.tmp <<'EOF' +ANSWER +EOF +"$(cat graphify-out/.graphify_python)" -m graphify save-result --question "Explain NODE_NAME" --answer-file graphify-out/.save_result_answer.tmp --type explain --nodes NODE_NAME ``` diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 16683fd92e..70195e907d 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1253,6 +1253,27 @@ def _is_input_path_slash_guidance_line(line: str) -> bool: return "substitute it with forward slashes" in line.lower() +def _is_save_result_answer_file_fix_line(line: str) -> bool: + """Whether a line is part of the #3621 review save-result answer file fix. + + ANSWER, the agent's own free text explanation, was spliced directly into + a double quoted --answer "ANSWER" shell argument, so an ordinary quote, + backtick, or dollar sign anywhere in a normal explanation broke or + hijacked the command. ANSWER is now captured through a single quoted + heredoc into a temp file first, then passed via --answer-file instead, + never re-parsed as shell syntax. The heredoc's own opener, its ANSWER + placeholder body, and its closing EOF marker are new lines with no + counterpart in pristine v8; the changed save-result command line itself + already matches _is_quoted_interpreter_cat_fix_line. + """ + stripped = line.strip() + return ( + stripped == "cat > graphify-out/.save_result_answer.tmp <<'EOF'" + or stripped == "ANSWER" + or stripped == "EOF" + ) + + # Every line that may differ between a rendered monolith and its pristine v8 # baseline. Each predicate documents one sanctioned change-class; a blank line is # allowed because the multi-line fix blocks insert spacing. Anything else failing @@ -1279,6 +1300,7 @@ def _is_input_path_slash_guidance_line(line: str) -> bool: _is_install_failure_gate_fix_line, _is_update_backup_reorder_fix_line, _is_quoted_interpreter_cat_fix_line, + _is_save_result_answer_file_fix_line, ) From 7037336169097c811bb07c4e01e64b29763f0e65 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:32:50 +0530 Subject: [PATCH 32/36] Add a regression test for the save result answer heredoc fix Covers the review finding directly: the old direct substitution answer form must not survive anywhere, and every host must capture the answer through the heredoc and read it back from the file afterward. Confirmed against pre fix code by restoring the prior fragment sources directly, the test fails there and passes only with the fix applied. --- tests/test_skillgen.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index 40755d0bc4..4fd28d4c04 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -768,6 +768,33 @@ def test_input_path_quote_escaping_guidance_is_present(): ) +def test_save_result_answer_is_captured_through_a_heredoc_not_inlined(): + """Review finding on PR 3621: ANSWER, the agent's own free text + explanation, was spliced directly into a double quoted + --answer "ANSWER" shell argument, so an ordinary quote, backtick, or + dollar sign anywhere in a normal explanation broke or hijacked the + command -- not just an adversarial input, everyday technical prose + routinely contains those characters. ANSWER must now be captured + through a single quoted heredoc into a temp file first, then passed + via --answer-file, which is never re-parsed as shell syntax.""" + claude_core, claude_refs = _platform_artifacts("claude") + platforms = gen.load_platforms() + bodies = {"claude": claude_core + "".join(claude_refs.values())} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + assert '--answer "ANSWER"' not in body, ( + f"[{key}] the old direct-substitution --answer form must not survive" + ) + assert "cat > graphify-out/.save_result_answer.tmp <<'EOF'" in body, ( + f"[{key}] missing the heredoc capture for the save-result answer" + ) + assert "--answer-file graphify-out/.save_result_answer.tmp" in body, ( + f"[{key}] save-result must read the answer back from the captured file" + ) + + def test_step1_gates_on_a_still_failed_install(): """#1619 B4: a failed install must stop with an actionable error instead of silently writing a broken interpreter path that fails every later step From 4469fb7ded8f2218e328078c8991e1e2c63916d5 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:34:18 +0530 Subject: [PATCH 33/36] Add changelog entries for the two new review finding fixes Covers the quote escaping guidance addition and the save result answer heredoc capture, alongside the existing issue 1619 entries this branch already carries. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8628042f18..8561ce1db6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,8 @@ Full release notes with details on each version: [GitHub Releases](https://githu - Fix: `/graphify` skill Step 1 now stops with an actionable error when the interpreter install still fails after the retry, instead of silently writing a broken interpreter path that every later step then failed against with a cryptic error far removed from the real cause (#1619, thanks @edtrackai). - Fix: a Windows path substituted into the `/graphify` skill's `INPUT_PATH` placeholder with backslashes corrupted the Python string literal it lands in (a lone `\t` becomes a tab, `\U` raises a `SyntaxError`). Every host now tells the agent to substitute forward slashes instead, and the PowerShell scan root save reads the path back out of a single quoted here string it captured INPUT_PATH into (rather than substituting it directly into the Resolve-Path call), which also means a path containing a space survives (#1619, thanks @edtrackai; folded into the #3642 here string fix once that shipped, see 0.9.68 above). - Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label. Step 4's write also now passes through the placeholder "Full Corpus" community label it already computes, since it is the only write for that path and every node was silently ending up with no `community_name` at all without it (#1619, thanks @edtrackai). +- Fix: every occurrence of `INPUT_PATH` substituted into a Python string literal now also tells the agent to escape a literal single quote in the path (e.g. a user directory containing an apostrophe), the same class of corruption the existing backslash guidance already covered for a different character (#1619, thanks @edtrackai). +- Fix: the `/graphify` skill's `save-result` calls spliced the agent's own free-text answer directly into a double-quoted shell argument, so an ordinary quote, backtick, or dollar sign anywhere in a normal technical explanation broke or hijacked the command — not just an adversarial one. The answer is now captured through a single-quoted heredoc into a temp file first, then passed through the existing `--answer-file` option instead of being spliced inline (#1619, thanks @edtrackai). - Feature: Elixir `alias`/`import`/`require`/`use` targets now resolve onto the module's `defmodule` node across files, so the internal module dependency graph is no longer dropped as dangling. Only top-level modules are indexed (a nested `defmodule`, labeled with its bare inner name, cannot capture an unrelated `use ` from another file), and a same-file reference is left unresolved so it cannot clobber the structural `contains` edge (#3603, thanks @ayushcodes10). - Feature: a Rust `self.method()` call now resolves to a method defined on the same type in another file (the common split-`impl`-block layout), pooling methods across every `impl` of one type and refusing to link when two unrelated types share a bare name (#3602, thanks @ayushcodes10). - Feature: a Ruby member call `obj.foo` on a known-type receiver now resolves to a method `foo` inherited from a superclass, including across files, using the same conservative promotion as the implicit-self resolver — a single owning class, matching method kind, and one unambiguous ancestry chain, or it stays dangling (#3585, thanks @oleksii-tumanov). From ed7cfe62b861dc866a783fdce867f30156d8acad Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:44:47 +0530 Subject: [PATCH 34/36] Capture graphify add's ingest arguments through files too URL, AUTHOR, and CONTRIBUTOR were spliced directly into single quoted Python string literals inside a graphify add call, the same class of gap that made the earlier issue 1619 quote escaping guidance necessary one level up, except here an embedded quote does not just corrupt a string, it breaks out of the literal and lets arbitrary Python run inside the interpreter block. AUTHOR and CONTRIBUTOR are free text that can be lifted verbatim from a fetched page, so this is not an adversarial only concern. This pattern lives in the shared add and watch reference every file write capable platform loads, not only in the aider and devin monolith copies issue 3640 originally flagged, so all three sources needed the same treatment. Each value is now captured through its own single quoted heredoc into a temp file first, then read back as a plain string, never re parsed as Python source, the same technique the save result answer fix just used one section above. Sanctioned the new heredoc and read back lines against the monolith round trip guard. Fixes issue 3640. --- graphify/skill-aider.md | 15 +++++++++- graphify/skill-devin.md | 15 +++++++++- .../skills/agents/references/add-watch.md | 15 +++++++++- graphify/skills/amp/references/add-watch.md | 15 +++++++++- .../skills/claude/references/add-watch.md | 15 +++++++++- graphify/skills/claw/references/add-watch.md | 15 +++++++++- graphify/skills/codex/references/add-watch.md | 15 +++++++++- .../skills/copilot/references/add-watch.md | 15 +++++++++- graphify/skills/droid/references/add-watch.md | 15 +++++++++- graphify/skills/kilo/references/add-watch.md | 15 +++++++++- graphify/skills/kiro/references/add-watch.md | 15 +++++++++- .../skills/opencode/references/add-watch.md | 15 +++++++++- graphify/skills/pi/references/add-watch.md | 15 +++++++++- graphify/skills/trae/references/add-watch.md | 15 +++++++++- .../skills/vscode/references/add-watch.md | 15 +++++++++- .../skills/windows/references/add-watch.md | 15 +++++++++- .../expected/graphify__skill-aider.md | 15 +++++++++- .../expected/graphify__skill-devin.md | 15 +++++++++- ...__skills__agents__references__add-watch.md | 15 +++++++++- ...ify__skills__amp__references__add-watch.md | 15 +++++++++- ...__skills__claude__references__add-watch.md | 15 +++++++++- ...fy__skills__claw__references__add-watch.md | 15 +++++++++- ...y__skills__codex__references__add-watch.md | 15 +++++++++- ..._skills__copilot__references__add-watch.md | 15 +++++++++- ...y__skills__droid__references__add-watch.md | 15 +++++++++- ...fy__skills__kilo__references__add-watch.md | 15 +++++++++- ...fy__skills__kiro__references__add-watch.md | 15 +++++++++- ...skills__opencode__references__add-watch.md | 15 +++++++++- ...hify__skills__pi__references__add-watch.md | 15 +++++++++- ...fy__skills__trae__references__add-watch.md | 15 +++++++++- ...__skills__vscode__references__add-watch.md | 15 +++++++++- ..._skills__windows__references__add-watch.md | 15 +++++++++- tools/skillgen/fragments/core/aider.md | 15 +++++++++- tools/skillgen/fragments/core/devin.md | 15 +++++++++- .../fragments/references/shared/add-watch.md | 15 +++++++++- tools/skillgen/gen.py | 29 +++++++++++++++++++ 36 files changed, 519 insertions(+), 35 deletions(-) diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index b1b072e5dc..7718729663 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -1228,13 +1228,26 @@ EOF Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 52ed18186f..20fba47811 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -1361,13 +1361,26 @@ EOF Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/agents/references/add-watch.md b/graphify/skills/agents/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/agents/references/add-watch.md +++ b/graphify/skills/agents/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/amp/references/add-watch.md b/graphify/skills/amp/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/amp/references/add-watch.md +++ b/graphify/skills/amp/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/claude/references/add-watch.md b/graphify/skills/claude/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/claude/references/add-watch.md +++ b/graphify/skills/claude/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/claw/references/add-watch.md b/graphify/skills/claw/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/claw/references/add-watch.md +++ b/graphify/skills/claw/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/codex/references/add-watch.md b/graphify/skills/codex/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/codex/references/add-watch.md +++ b/graphify/skills/codex/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/copilot/references/add-watch.md b/graphify/skills/copilot/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/copilot/references/add-watch.md +++ b/graphify/skills/copilot/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/droid/references/add-watch.md b/graphify/skills/droid/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/droid/references/add-watch.md +++ b/graphify/skills/droid/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/kilo/references/add-watch.md b/graphify/skills/kilo/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/kilo/references/add-watch.md +++ b/graphify/skills/kilo/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/kiro/references/add-watch.md b/graphify/skills/kiro/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/kiro/references/add-watch.md +++ b/graphify/skills/kiro/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/opencode/references/add-watch.md b/graphify/skills/opencode/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/opencode/references/add-watch.md +++ b/graphify/skills/opencode/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/pi/references/add-watch.md b/graphify/skills/pi/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/pi/references/add-watch.md +++ b/graphify/skills/pi/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/trae/references/add-watch.md b/graphify/skills/trae/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/trae/references/add-watch.md +++ b/graphify/skills/trae/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/vscode/references/add-watch.md b/graphify/skills/vscode/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/vscode/references/add-watch.md +++ b/graphify/skills/vscode/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/graphify/skills/windows/references/add-watch.md b/graphify/skills/windows/references/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/graphify/skills/windows/references/add-watch.md +++ b/graphify/skills/windows/references/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index b1b072e5dc..7718729663 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -1228,13 +1228,26 @@ EOF Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 52ed18186f..20fba47811 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -1361,13 +1361,26 @@ EOF Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md b/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md b/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md b/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md b/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md b/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md b/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md b/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md b/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md b/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md b/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md b/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md b/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md b/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md b/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index b1b072e5dc..7718729663 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -1228,13 +1228,26 @@ EOF Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 52ed18186f..20fba47811 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -1361,13 +1361,26 @@ EOF Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/fragments/references/shared/add-watch.md b/tools/skillgen/fragments/references/shared/add-watch.md index f76d3245b8..c6e889455f 100644 --- a/tools/skillgen/fragments/references/shared/add-watch.md +++ b/tools/skillgen/fragments/references/shared/add-watch.md @@ -7,13 +7,26 @@ Load this when the user ran `/graphify add ` or passed `--watch`. Neither i Fetch a URL and add it to the corpus, then update the graph. ```bash +cat > graphify-out/.ingest_url.tmp <<'EOF' +URL +EOF +cat > graphify-out/.ingest_author.tmp <<'EOF' +AUTHOR +EOF +cat > graphify-out/.ingest_contributor.tmp <<'EOF' +CONTRIBUTOR +EOF "$(cat graphify-out/.graphify_python)" -c " import sys from graphify.ingest import ingest from pathlib import Path +_url = Path('graphify-out/.ingest_url.tmp').read_text(encoding='utf-8').strip() +_author = Path('graphify-out/.ingest_author.tmp').read_text(encoding='utf-8').strip() +_contributor = Path('graphify-out/.ingest_contributor.tmp').read_text(encoding='utf-8').strip() + try: - out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR') + out = ingest(_url, Path('./raw'), author=_author, contributor=_contributor) print(f'Saved to {out}') except ValueError as e: print(f'error: {e}', file=sys.stderr) diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 70195e907d..f1d769fd89 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1274,6 +1274,34 @@ def _is_save_result_answer_file_fix_line(line: str) -> bool: ) +def _is_ingest_add_file_fix_line(line: str) -> bool: + """Whether a line is part of the issue 3640 graphify add file capture fix. + + URL/AUTHOR/CONTRIBUTOR were spliced directly into single quoted Python + string literals inside ingest('URL', ..., author='AUTHOR', + contributor='CONTRIBUTOR'). A value containing an embedded quote breaks + out of the literal, and since AUTHOR/CONTRIBUTOR can be free text lifted + from a fetched page, this is not just a corruption risk. Each value is + now captured through its own single quoted heredoc into a temp file + first, then read back as a plain string, never re-parsed as Python + source. The three heredoc openers, their placeholder bodies, the three + read_text lines, and both the old and new ingest(...) call lines are new + or changed with no counterpart in pristine v8. + """ + stripped = line.strip() + if stripped in ( + "cat > graphify-out/.ingest_url.tmp <<'EOF'", + "cat > graphify-out/.ingest_author.tmp <<'EOF'", + "cat > graphify-out/.ingest_contributor.tmp <<'EOF'", + "URL", + "AUTHOR", + "CONTRIBUTOR", + "EOF", + ): + return True + return "graphify-out/.ingest_" in line or "ingest(_url, Path" in line or "ingest('URL', Path" in line + + # Every line that may differ between a rendered monolith and its pristine v8 # baseline. Each predicate documents one sanctioned change-class; a blank line is # allowed because the multi-line fix blocks insert spacing. Anything else failing @@ -1301,6 +1329,7 @@ def _is_save_result_answer_file_fix_line(line: str) -> bool: _is_update_backup_reorder_fix_line, _is_quoted_interpreter_cat_fix_line, _is_save_result_answer_file_fix_line, + _is_ingest_add_file_fix_line, ) From e16e7bb59a0be58176eff947dc4e7aaf3a5095e2 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:44:53 +0530 Subject: [PATCH 35/36] Add a regression test for the ingest file capture fix Covers issue 3640 directly across claude, aider, and devin: the old direct substitution ingest call must not survive anywhere, and every host must capture url, author, and contributor through their own heredoc and read each back from its file afterward before calling ingest. Confirmed against pre fix code by restoring the prior fragment sources directly, the test fails there and passes only with the fix applied. --- tests/test_skillgen.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index 4fd28d4c04..bf6bf118a4 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -795,6 +795,39 @@ def test_save_result_answer_is_captured_through_a_heredoc_not_inlined(): ) +def test_ingest_add_call_captures_url_author_contributor_through_files(): + """Issue 3640: URL/AUTHOR/CONTRIBUTOR were spliced directly into single + quoted Python string literals inside ingest('URL', ..., author='AUTHOR', + contributor='CONTRIBUTOR'). AUTHOR/CONTRIBUTOR are free text that can be + lifted verbatim from a fetched page, and even an ordinary embedded quote + breaks out of the literal and lets arbitrary Python run inside the -c + script. This affects every host with a /graphify add flow, not just + aider/devin -- the shared add-watch reference all the file-write-capable + platforms load has the exact same pattern. Each value must now be + captured through its own single quoted heredoc into a temp file first, + then read back as a plain string, never re-parsed as Python source.""" + claude_core, claude_refs = _platform_artifacts("claude") + platforms = gen.load_platforms() + bodies = {"claude": claude_core + "".join(claude_refs.values())} + for key in ("aider", "devin"): + bodies[key] = gen.render(platforms[key])[0].content + + for key, body in bodies.items(): + assert "ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR')" not in body, ( + f"[{key}] the old direct-substitution ingest(...) form must not survive" + ) + for tmp_name in ("url", "author", "contributor"): + assert f"cat > graphify-out/.ingest_{tmp_name}.tmp <<'EOF'" in body, ( + f"[{key}] missing the heredoc capture for ingest's {tmp_name}" + ) + assert f"Path('graphify-out/.ingest_{tmp_name}.tmp').read_text" in body, ( + f"[{key}] must read {tmp_name} back from its captured file" + ) + assert "ingest(_url, Path('./raw'), author=_author, contributor=_contributor)" in body, ( + f"[{key}] ingest(...) must be called with the file-captured values" + ) + + def test_step1_gates_on_a_still_failed_install(): """#1619 B4: a failed install must stop with an actionable error instead of silently writing a broken interpreter path that fails every later step From 93a961be27972efacda8d9269fda14772863e6f7 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Sat, 26 Sep 2026 14:45:58 +0530 Subject: [PATCH 36/36] Add a changelog entry for the ingest file capture fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8561ce1db6..3750779689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Full release notes with details on each version: [GitHub Releases](https://githu - Fix: the `/graphify` skill's `--no-cluster` and `--force` flags are now actually implemented instead of being referenced but never wired through. Step 2 suggested `--no-cluster` for a flat corpus and the shrink-guard error message suggested `--force`, but Step 4 called `cluster()` unconditionally and `to_json()` never received `force=`, so neither flag could do anything. Step 4 now builds a single "Full Corpus" community instead of clustering when `--no-cluster` is given, both `to_json()` calls honor `force=`, and Step 5's labeling is skipped when there is nothing to label. Step 4's write also now passes through the placeholder "Full Corpus" community label it already computes, since it is the only write for that path and every node was silently ending up with no `community_name` at all without it (#1619, thanks @edtrackai). - Fix: every occurrence of `INPUT_PATH` substituted into a Python string literal now also tells the agent to escape a literal single quote in the path (e.g. a user directory containing an apostrophe), the same class of corruption the existing backslash guidance already covered for a different character (#1619, thanks @edtrackai). - Fix: the `/graphify` skill's `save-result` calls spliced the agent's own free-text answer directly into a double-quoted shell argument, so an ordinary quote, backtick, or dollar sign anywhere in a normal technical explanation broke or hijacked the command — not just an adversarial one. The answer is now captured through a single-quoted heredoc into a temp file first, then passed through the existing `--answer-file` option instead of being spliced inline (#1619, thanks @edtrackai). +- Security: `/graphify add`'s `ingest(...)` call spliced the URL, author, and contributor directly into single-quoted Python string literals; an embedded quote in either free-text field (author/contributor can be lifted verbatim from a fetched page) breaks out of the literal and runs arbitrary Python inside the interpreter block. Affects every host with an `add`/`--watch` flow, not just the aider/devin monolith copies originally flagged. Each value is now captured through its own single-quoted heredoc into a temp file first, then read back as a plain string (#3640, thanks @ayushcodes10). - Feature: Elixir `alias`/`import`/`require`/`use` targets now resolve onto the module's `defmodule` node across files, so the internal module dependency graph is no longer dropped as dangling. Only top-level modules are indexed (a nested `defmodule`, labeled with its bare inner name, cannot capture an unrelated `use ` from another file), and a same-file reference is left unresolved so it cannot clobber the structural `contains` edge (#3603, thanks @ayushcodes10). - Feature: a Rust `self.method()` call now resolves to a method defined on the same type in another file (the common split-`impl`-block layout), pooling methods across every `impl` of one type and refusing to link when two unrelated types share a bare name (#3602, thanks @ayushcodes10). - Feature: a Ruby member call `obj.foo` on a known-type receiver now resolves to a method `foo` inherited from a superclass, including across files, using the same conservative promotion as the implicit-self resolver — a single owning class, matching method kind, and one unambiguous ancestry chain, or it stays dangling (#3585, thanks @oleksii-tumanov).