diff --git a/graphify/cli.py b/graphify/cli.py index 6642f57d52..f32cdf929e 100644 --- a/graphify/cli.py +++ b/graphify/cli.py @@ -3874,6 +3874,8 @@ def _ctx_identity(source_file) -> str | None: } if deep_mode: corpus_kwargs["deep_mode"] = True + if ast_result: + corpus_kwargs["ast_data"] = ast_result if cli_token_budget is not None: corpus_kwargs["token_budget"] = cli_token_budget if cli_max_concurrency is not None: diff --git a/graphify/extract.py b/graphify/extract.py index e015c9d715..05a4f69827 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -7364,6 +7364,228 @@ def _ignored(p: Path) -> bool: return sorted(results) + +_SCOPER_GENERIC_IDENTIFIERS = frozenset({ + "run", "get", "set", "parse", "data", "error", "test", "init", "main", + "build", "load", "save", "clean", "start", "stop", "read", "write", + "send", "recv", "node", "edge", "type", "name", "file", "path", + "item", "list", "dict", "base", "core", "help", "view", "call", + "calc", "make", "show", "hide", "drop", "find", "check", "info", + "true", "false", "none", "null", "self", "this", "args", "kwargs", + "text", "code", "user", "root", "from", "into", "with", "open", + "class", "func", "function", "method", "module", "package", "import", +}) + + +def scope_ast_inventory( + ast_data: dict, + doc_paths: list[Path | str], + doc_texts: list[str] | None = None, + max_symbols: int = 100, +) -> str: + """Derive a compact, deterministically scoped inventory of relevant AST symbols + for a semantic document chunk without re-reading source code files. + + Returns a newline-separated string formatted as: + id | qualified_name | source_file + or "None available" if no relevant symbols match. + """ + if not isinstance(ast_data, dict): + return "None available" + + nodes = [n for n in ast_data.get("nodes", []) if isinstance(n, dict) and n.get("id")] + if not nodes: + return "None available" + + edges = [e for e in ast_data.get("edges", []) if isinstance(e, dict)] + nodes_by_id = {n["id"]: n for n in nodes} + + def _posix_path_str(p: object) -> str: + if not p: + return "" + return str(p).replace("\\", "/") + + # Index by source_file and basename + nodes_by_file: dict[str, list[dict]] = {} + for n in nodes: + sf = n.get("source_file") + if sf: + posix_sf = _posix_path_str(sf) + nodes_by_file.setdefault(posix_sf, []).append(n) + + basename_to_files: dict[str, set[str]] = {} + for sf in nodes_by_file: + bname = sf.split("/")[-1].lower() + basename_to_files.setdefault(bname, set()).add(sf) + + # Parent-child containment maps from AST edges + parent_map: dict[str, str] = {} + children_map: dict[str, list[str]] = {} + for e in edges: + rel = e.get("relation") + src = e.get("source") + tgt = e.get("target") + if rel in ("method", "contains") and src and tgt: + parent_map[tgt] = src + children_map.setdefault(src, []).append(tgt) + + def get_qualified_name(n: dict) -> str: + label = str(n.get("label", "")).strip() + nid = n.get("id", "") + sf = _posix_path_str(n.get("source_file", "")) + file_bname = sf.split("/")[-1] if sf else "" + + def _is_file_label(lbl: str) -> bool: + return ( + lbl == file_bname + or lbl.endswith(( + ".py", ".ts", ".js", ".go", ".rs", ".java", ".cs", ".cpp", ".c", ".h", + ".tsx", ".jsx", ".rb", ".php", ".swift", ".kt", ".scala", ".zig" + )) + ) + + if _is_file_label(label): + return label + + # Traverse ancestors up to the file/root boundary + ancestors: list[str] = [] + curr_id = nid + visited = {curr_id} + while True: + pid = parent_map.get(curr_id) + if not pid or pid in visited or pid not in nodes_by_id: + break + visited.add(pid) + parent_node = nodes_by_id[pid] + p_label = str(parent_node.get("label", "")).strip() + if _is_file_label(p_label): + break + ancestors.append(p_label.rstrip("()")) + curr_id = pid + + if not ancestors: + return label + + ancestor_chain = ".".join(reversed(ancestors)) + if label.startswith("."): + return f"{ancestor_chain}{label}" + return f"{ancestor_chain}.{label}" + + # Collect document text + texts: list[str] = [] + if doc_texts is not None and len(doc_texts) == len(doc_paths): + texts.extend(doc_texts) + else: + if doc_texts: + texts.extend(doc_texts) + for dp in doc_paths: + texts.append(str(dp)) + p = Path(dp) if not isinstance(dp, Path) else dp + if p.is_file(): + try: + texts.append(p.read_text(encoding="utf-8", errors="replace")) + except Exception: + pass + + full_text = " ".join(texts) + if not full_text.strip(): + return "None available" + + full_text_lower = full_text.lower() + + # Tier 1: Path & unique basename matching + tier1_nodes: list[dict] = [] + for sf, fnodes in nodes_by_file.items(): + sf_posix = _posix_path_str(sf) + sf_lower = sf_posix.lower() + if sf_lower in full_text_lower or sf_posix in full_text: + tier1_nodes.extend(fnodes) + continue + # Unique basename check + bname = sf_posix.split("/")[-1].lower() + if len(basename_to_files.get(bname, set())) == 1: + raw_bname = sf_posix.split("/")[-1] + if re.search(rf"(?= 4 chars, non-generic) + # Matches against symbol names/labels (file nodes are handled by Tier 1) + doc_tokens_lower = { + t.lower() + for t in re.findall(r"[A-Za-z_][A-Za-z0-9_]*", full_text) + if len(t) >= 4 and t.lower() not in _SCOPER_GENERIC_IDENTIFIERS + } + + tier2_nodes: list[dict] = [] + for n in nodes: + sf = _posix_path_str(n.get("source_file", "")) + file_bname = sf.split("/")[-1] if sf else "" + lbl = str(n.get("label", "")).strip() + # Skip file nodes in Tier 2 — file nodes are handled by Tier 1 (path/unique basename) + if sf and lbl == file_bname: + continue + + idents: set[str] = set() + qname = get_qualified_name(n) + for piece in (lbl, qname): + for token in re.findall(r"[A-Za-z_][A-Za-z0-9_]*", piece): + if len(token) >= 4 and token.lower() not in _SCOPER_GENERIC_IDENTIFIERS: + idents.add(token.lower()) + if idents & doc_tokens_lower: + tier2_nodes.append(n) + + # Tier 3: Containment expansion + tier3_nodes: list[dict] = [] + selected_ids = {n["id"] for n in tier1_nodes if "id" in n} | {n["id"] for n in tier2_nodes if "id" in n} + for nid in list(selected_ids): + for child_id in children_map.get(nid, []): + if child_id in nodes_by_id and child_id not in selected_ids: + tier3_nodes.append(nodes_by_id[child_id]) + selected_ids.add(child_id) + + # Ensure file node for every matched symbol is also present + for n in list(tier1_nodes) + list(tier2_nodes) + list(tier3_nodes): + sf = n.get("source_file") + if sf: + posix_sf = _posix_path_str(sf) + if posix_sf in nodes_by_file: + for fn in nodes_by_file[posix_sf]: + file_bname = posix_sf.split("/")[-1] + if str(fn.get("label", "")).strip() == file_bname: + fn_id = fn.get("id") + if fn_id and fn_id not in selected_ids: + tier3_nodes.append(fn) + selected_ids.add(fn_id) + + def sort_key(n: dict) -> tuple[str, str, str]: + sf = _posix_path_str(n.get("source_file", "")) + return (sf, get_qualified_name(n), str(n.get("id", ""))) + + seen: set[str] = set() + ordered_candidates: list[dict] = [] + for tier in (tier1_nodes, tier2_nodes, tier3_nodes): + tier_unique = [] + for n in tier: + nid = n.get("id") + if nid and nid not in seen: + seen.add(nid) + tier_unique.append(n) + tier_unique.sort(key=sort_key) + ordered_candidates.extend(tier_unique) + + if not ordered_candidates: + return "None available" + + final_selection = ordered_candidates[:max_symbols] + final_selection.sort(key=sort_key) + + lines = [ + f"{n['id']} | {get_qualified_name(n)} | {_posix_path_str(n.get('source_file', ''))}" + for n in final_selection + ] + return "\n".join(lines) + + if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python -m graphify.extract ...", file=sys.stderr) diff --git a/graphify/llm.py b/graphify/llm.py index 75f6378818..8730a00f28 100644 --- a/graphify/llm.py +++ b/graphify/llm.py @@ -516,11 +516,23 @@ def _thinking_disabled_via_env() -> bool: """ -def _extraction_system(*, deep: bool = False) -> str: - """Return the semantic-extraction system prompt, optionally in deep mode.""" - if not deep: - return _EXTRACTION_SYSTEM - return _EXTRACTION_SYSTEM + _DEEP_EXTRACTION_SUFFIX +def _extraction_system(*, deep: bool = False, code_symbols: str | None = None) -> str: + """Return the semantic-extraction system prompt, optionally in deep mode and with code symbols.""" + prompt = _EXTRACTION_SYSTEM + if code_symbols and code_symbols.strip() and code_symbols.strip() != "None available": + prompt += f"""\ + +Code Symbol Inventory (canonical code symbols available for this chunk): +{code_symbols} + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory as the edge target. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate file_type="code" node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. +""" + if deep: + prompt += _DEEP_EXTRACTION_SUFFIX + return prompt def _file_to_text(path: Path) -> str: @@ -1361,6 +1373,7 @@ def _call_openai_compat( *, backend: str = "", deep_mode: bool = False, + code_symbols: str | None = None, images: list[_ImageRef] | None = None, extra_body: dict | None = None, ) -> dict: @@ -1391,7 +1404,7 @@ def _call_openai_compat( kwargs: dict = { "model": model, "messages": [ - {"role": "system", "content": _extraction_system(deep=deep_mode)}, + {"role": "system", "content": _extraction_system(deep=deep_mode, code_symbols=code_symbols)}, {"role": "user", "content": _openai_content(user_message, images or [])}, ], "max_completion_tokens": max_completion_tokens, @@ -1492,7 +1505,7 @@ def _call_openai_compat( return result -def _call_claude(api_key: str, model: str, user_message: str, max_tokens: int = 8192, *, deep_mode: bool = False, images: list[_ImageRef] | None = None) -> dict: +def _call_claude(api_key: str, model: str, user_message: str, max_tokens: int = 8192, *, deep_mode: bool = False, code_symbols: str | None = None, images: list[_ImageRef] | None = None) -> dict: """Call Anthropic Claude directly (not via OpenAI compat layer).""" try: import anthropic @@ -1508,7 +1521,7 @@ def _call_claude(api_key: str, model: str, user_message: str, max_tokens: int = resp = client.messages.create( model=model, max_tokens=max_tokens, - system=_extraction_system(deep=deep_mode), + system=_extraction_system(deep=deep_mode, code_symbols=code_symbols), messages=[{"role": "user", "content": _anthropic_content(user_message, images or [])}], ) raw_content = _anthropic_response_text(resp.content) @@ -1636,7 +1649,7 @@ def _claude_cli_supports_json_schema(claude_cmd: str) -> bool: return supported -def _call_claude_cli(user_message: str, max_tokens: int = 8192, *, deep_mode: bool = False, images: list[_ImageRef] | None = None) -> dict: +def _call_claude_cli(user_message: str, max_tokens: int = 8192, *, deep_mode: bool = False, code_symbols: str | None = None, images: list[_ImageRef] | None = None) -> dict: """Call Claude via the locally-installed Claude Code CLI (`claude -p`). Routes through the user's Claude Code subscription auth instead of a separate @@ -1704,7 +1717,7 @@ def _call_claude_cli(user_message: str, max_tokens: int = 8192, *, deep_mode: bo add_dir_args.extend(["--add-dir", d]) combined_message = ( - _extraction_system(deep=deep_mode) + _extraction_system(deep=deep_mode, code_symbols=code_symbols) + "\n\n---\n" + "Now extract the knowledge graph from the following source file(s) " + "and output ONLY the JSON object described above. No prose, no " @@ -1813,13 +1826,14 @@ def _call_azure( max_tokens: int = 8192, *, deep_mode: bool = False, + code_symbols: str | None = None, ) -> dict: """Call Azure OpenAI Service via the AzureOpenAI SDK client.""" client = _azure_client(api_key, endpoint) kwargs: dict = { "model": model, "messages": [ - {"role": "system", "content": _extraction_system(deep=deep_mode)}, + {"role": "system", "content": _extraction_system(deep=deep_mode, code_symbols=code_symbols)}, {"role": "user", "content": user_message}, ], "max_completion_tokens": max_tokens, @@ -1839,7 +1853,7 @@ def _call_azure( return result -def _call_bedrock(model: str, user_message: str, max_tokens: int = 8192, *, deep_mode: bool = False, images: list[_ImageRef] | None = None) -> dict: +def _call_bedrock(model: str, user_message: str, max_tokens: int = 8192, *, deep_mode: bool = False, code_symbols: str | None = None, images: list[_ImageRef] | None = None) -> dict: """Call AWS Bedrock via boto3 Converse API using the standard AWS credential chain.""" try: import boto3 @@ -1870,7 +1884,7 @@ def _call_bedrock(model: str, user_message: str, max_tokens: int = 8192, *, deep try: resp = client.converse( modelId=model, - system=[{"text": _extraction_system(deep=deep_mode)}], + system=[{"text": _extraction_system(deep=deep_mode, code_symbols=code_symbols)}], messages=[{"role": "user", "content": _bedrock_content(user_message, images or [])}], inferenceConfig=_bedrock_inference_config(max_tokens, model), ) @@ -1898,6 +1912,8 @@ def extract_files_direct( root: Path = Path("."), *, deep_mode: bool = False, + ast_data: dict | None = None, + code_symbols: str | None = None, ) -> dict: """Extract semantic nodes/edges from a list of files using the given backend. @@ -1957,14 +1973,19 @@ def extract_files_direct( image_refs = _build_image_refs(image_files, root, read_bytes=read_bytes) if image_files else [] if image_refs and not vision: image_refs = _strip_pixels(image_refs) + + if code_symbols is None and ast_data is not None: + from graphify.extract import scope_ast_inventory + code_symbols = scope_ast_inventory(ast_data, text_files + image_files) + max_out = _resolve_max_tokens(cfg.get("max_tokens", 8192)) if backend == "claude": - result = _call_claude(key, mdl, user_msg, max_tokens=max_out, deep_mode=deep_mode, images=image_refs) + result = _call_claude(key, mdl, user_msg, max_tokens=max_out, deep_mode=deep_mode, code_symbols=code_symbols, images=image_refs) elif backend == "claude-cli": - result = _call_claude_cli(user_msg, max_tokens=max_out, deep_mode=deep_mode, images=image_refs) + result = _call_claude_cli(user_msg, max_tokens=max_out, deep_mode=deep_mode, code_symbols=code_symbols, images=image_refs) elif backend == "bedrock": - result = _call_bedrock(mdl, user_msg, max_tokens=max_out, deep_mode=deep_mode, images=image_refs) + result = _call_bedrock(mdl, user_msg, max_tokens=max_out, deep_mode=deep_mode, code_symbols=code_symbols, images=image_refs) elif backend == "azure": endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT", "").strip() if not endpoint: @@ -1980,6 +2001,7 @@ def extract_files_direct( temperature=_resolve_temperature(cfg.get("temperature", 0), mdl), max_tokens=max_out, deep_mode=deep_mode, + code_symbols=code_symbols, ) else: result = _call_openai_compat( @@ -1998,6 +2020,7 @@ def extract_files_direct( ), backend=backend, deep_mode=deep_mode, + code_symbols=code_symbols, images=image_refs, extra_body=cfg.get("extra_body"), ) @@ -2273,6 +2296,8 @@ def _extract_with_adaptive_retry( _depth: int = 0, *, deep_mode: bool = False, + ast_data: dict | None = None, + code_symbols: str | None = None, ) -> dict: """Extract a chunk; if the response is truncated (`finish_reason="length"`), the API rejects the prompt as too large for the model's context window, or @@ -2318,10 +2343,10 @@ def _extract_with_adaptive_retry( """ def _merge_two(left_units, right_units) -> dict: left = _extract_with_adaptive_retry( - left_units, backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode + left_units, backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) right = _extract_with_adaptive_retry( - right_units, backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode + right_units, backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) return { "nodes": left.get("nodes", []) + right.get("nodes", []), @@ -2343,7 +2368,7 @@ def _split_lone_slice() -> "tuple[FileSlice, FileSlice] | None": try: result = extract_files_direct( - chunk, backend=backend, api_key=api_key, model=model, root=root, deep_mode=deep_mode + chunk, backend=backend, api_key=api_key, model=model, root=root, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) # A hollow response is retried as-is, with backoff — see _mark_hollow. # Bounded by a fixed number of attempts, so one misbehaving backend @@ -2364,7 +2389,7 @@ def _split_lone_slice() -> "tuple[FileSlice, FileSlice] | None": ) time.sleep(_delay) result = extract_files_direct( - chunk, backend=backend, api_key=api_key, model=model, root=root, deep_mode=deep_mode + chunk, backend=backend, api_key=api_key, model=model, root=root, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) except Exception as exc: # noqa: BLE001 — re-raise unless it's a known context overflow or timeout is_timeout = _looks_like_timeout(exc) @@ -2402,10 +2427,10 @@ def _split_lone_slice() -> "tuple[FileSlice, FileSlice] | None": ) mid = len(chunk) // 2 left = _extract_with_adaptive_retry( - chunk[:mid], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode + chunk[:mid], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) right = _extract_with_adaptive_retry( - chunk[mid:], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode + chunk[mid:], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) return { "nodes": left.get("nodes", []) + right.get("nodes", []), @@ -2458,12 +2483,13 @@ def _split_lone_slice() -> "tuple[FileSlice, FileSlice] | None": ) # The node set is incomplete; mark it so it is not promoted to the # semantic cache as authoritative and is re-dispatched next run. Also - # record the chunk's files so a truncation that parsed to nothing (an - # empty item set) still marks the file partial (#1950 empty-parse gap). + # propagate to _partial_files so a sliced single-file chunk attributes + # the underlying file correctly. _mark_partial(result) result["_partial_files"] = sorted( set(_chunk_partial_files(chunk)) | set(result.get("_partial_files", []) or []) ) + result["finish_reason"] = "stop" return result if _depth >= max_depth: @@ -2483,17 +2509,16 @@ def _split_lone_slice() -> "tuple[FileSlice, FileSlice] | None": return result print( - f"[graphify] chunk of {len(chunk)} truncated at depth {_depth}, " - f"splitting into halves of {len(chunk) // 2} and " - f"{len(chunk) - len(chunk) // 2}", + f"[graphify] chunk of {len(chunk)} truncated at max_completion_tokens at depth {_depth}; " + f"splitting in half and retrying", file=sys.stderr, ) mid = len(chunk) // 2 left = _extract_with_adaptive_retry( - chunk[:mid], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode + chunk[:mid], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) right = _extract_with_adaptive_retry( - chunk[mid:], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode + chunk[mid:], backend, api_key, model, root, max_depth, _depth + 1, deep_mode=deep_mode, ast_data=ast_data, code_symbols=code_symbols ) return { @@ -2503,7 +2528,9 @@ def _split_lone_slice() -> "tuple[FileSlice, FileSlice] | None": "input_tokens": left.get("input_tokens", 0) + right.get("input_tokens", 0), "output_tokens": left.get("output_tokens", 0) + right.get("output_tokens", 0), "model": result.get("model"), - # Both halves either succeeded or have already surfaced their own + # Truncation inside one of the halves is resolved before _merge_two / + # the mid-split returns; mark finish_reason as "stop" so the caller + # (e.g. CLI or parallel runner) does not surface a misleading top-level # truncation warning; the merged result is no longer truncated as a # logical unit. "finish_reason": "stop", @@ -2524,6 +2551,7 @@ def extract_corpus_parallel( max_retry_depth: int | None = None, deep_mode: bool = False, cache_root: "Path | None" = None, + ast_data: dict | None = None, ) -> dict: """Extract a corpus in chunks, merging results. @@ -2606,6 +2634,7 @@ def _run_one(idx: int, chunk: list[Path]) -> tuple[int, dict | None, Exception | root=root, max_depth=max_retry_depth, deep_mode=deep_mode, + ast_data=ast_data, ) result["elapsed_seconds"] = round(time.time() - t0, 2) return idx, result, None @@ -2645,6 +2674,8 @@ def _checkpoint_chunk(result: dict, chunk: "list[Path | FileSlice]") -> None: # Deep-mode results checkpoint into their own namespace # (cache/semantic-deep/) so a deep run never overwrites standard # entries — and a later standard run never serves deep ones (#1894). + from graphify.extract import scope_ast_inventory + chunk_symbols = scope_ast_inventory(ast_data, [unit_path(item) for item in chunk]) if ast_data else None _scs( result.get("nodes", []), result.get("edges", []), @@ -2657,7 +2688,7 @@ def _checkpoint_chunk(result: dict, chunk: "list[Path | FileSlice]") -> None: # Stamp the entry with the prompt that produced it, so a release # that changes _EXTRACTION_SYSTEM re-extracts instead of replaying # this vintage forever (#1939). - prompt=_extraction_system(deep=deep_mode), + prompt=_extraction_system(deep=deep_mode, code_symbols=chunk_symbols), # A truncated/partial chunk must not be checkpointed as # authoritative: pass the partial file set so its entry is # stamped ``partial: True`` and re-dispatched next run. diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 190827d9ac..7bdf5f242a 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -258,7 +256,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -271,7 +269,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 4996beb787..57fa1c8992 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -179,13 +179,11 @@ This step has two parts: **structural extraction** (deterministic, free) and **s > **graphify needs no API key. Never ask the user for one, and never block on one.** Code is extracted structurally (AST) with no LLM and no key at all — a code-only corpus (the common `/graphify .` on a repo) skips semantic extraction entirely, so go straight to Part A and skip Part B. Semantic extraction (only for docs, papers, and images) is done by your own model. graphify does **not** read `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or any other provider key. If you cannot dispatch subagents, do not stall: a code-only corpus has no semantic work (write the empty semantic file and continue to Part C); for docs/papers/images, extract them inline yourself. If you catch yourself about to prompt for or block on a missing API key, that is a misread of this skill — proceed without one. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 190827d9ac..7bdf5f242a 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -258,7 +256,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -271,7 +269,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index abd2811d23..ed7925cc41 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index af3f723c78..0c916523e5 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -259,7 +257,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Call `spawn_agent` once per chunk — ALL in the same response so they run in parallel. Build the message by wrapping the extraction prompt in task-delegation framing: ``` -spawn_agent(agent_type="worker", message="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +spawn_agent(agent_type="worker", message="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` After all agents are dispatched, collect results sequentially in memory: @@ -271,7 +269,7 @@ Parse each result as JSON. Accumulate nodes/edges/hyperedges across all results Subagent prompt template: -See `references/extraction-spec.md` for the compact subagent prompt (rules, node-ID format, confidence rubric, hyperedge and vision rules, JSON schema). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted, and have it return the JSON inline. +See `references/extraction-spec.md` for the compact subagent prompt (rules, node-ID format, confidence rubric, hyperedge and vision rules, code symbol inventory, JSON schema). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted, and have it return the JSON inline. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index abd2811d23..ed7925cc41 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index f9be846cbf..347bcb2b24 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -192,13 +192,11 @@ This step has two parts: **structural extraction** (deterministic, free) and **s > **graphify needs no API key. Never ask the user for one, and never block on one.** Code is extracted structurally (AST) with no LLM and no key at all — a code-only corpus (the common `/graphify .` on a repo) skips semantic extraction entirely, so go straight to Part A and skip Part B. Semantic extraction (only for docs, papers, and images) is done by your own model. graphify does **not** read `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or any other provider key. If you cannot dispatch subagents, do not stall: a code-only corpus has no semantic work (write the empty semantic file and continue to Part C); for docs/papers/images, extract them inline yourself. If you catch yourself about to prompt for or block on a missing API key, that is a misread of this skill — proceed without one. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index fd148d485d..a72775326a 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -258,7 +256,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -271,7 +269,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index 3e70b050a4..d505f669a7 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index abd2811d23..ed7925cc41 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 91ced60675..8581c8716f 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -257,7 +255,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Dispatch one `@mention` per chunk — ALL in the same response: ``` -@agent Chunk CHUNK_NUM of TOTAL_CHUNKS: [extraction prompt with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted] +@agent Chunk CHUNK_NUM of TOTAL_CHUNKS: [extraction prompt with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted] @agent Chunk 2 of TOTAL_CHUNKS: [next chunk] ``` @@ -266,7 +264,7 @@ Wait for all agents to return. Parse each response as JSON. Accumulate nodes/edg Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index abd2811d23..ed7925cc41 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 050667bc20..9ab7480262 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -259,7 +257,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -272,7 +270,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 20c7c0835c..fad1f906f7 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -270,7 +268,7 @@ Repeat for every chunk. Each chunk's JSON must land in its own `graphify-out/.gr Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted, and write its response to that chunk's file. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted, and write its response to that chunk's file. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index b09ecca3c4..3bd88c41de 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -190,13 +190,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```powershell @' @@ -291,7 +289,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```powershell @@ -301,7 +299,7 @@ $PROJECT_ROOT = (Get-Location).Path # cwd — where Part C globs graphify-out\ Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skill.md b/graphify/skill.md index abd2811d23..ed7925cc41 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/graphify/skills/agents/references/extraction-spec.md b/graphify/skills/agents/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/agents/references/extraction-spec.md +++ b/graphify/skills/agents/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/amp/references/extraction-spec.md b/graphify/skills/amp/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/amp/references/extraction-spec.md +++ b/graphify/skills/amp/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/claude/references/extraction-spec.md b/graphify/skills/claude/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/claude/references/extraction-spec.md +++ b/graphify/skills/claude/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/copilot/references/extraction-spec.md b/graphify/skills/copilot/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/copilot/references/extraction-spec.md +++ b/graphify/skills/copilot/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/droid/references/extraction-spec.md b/graphify/skills/droid/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/droid/references/extraction-spec.md +++ b/graphify/skills/droid/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/kilo/references/extraction-spec.md b/graphify/skills/kilo/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/kilo/references/extraction-spec.md +++ b/graphify/skills/kilo/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/opencode/references/extraction-spec.md b/graphify/skills/opencode/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/opencode/references/extraction-spec.md +++ b/graphify/skills/opencode/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/trae/references/extraction-spec.md b/graphify/skills/trae/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/trae/references/extraction-spec.md +++ b/graphify/skills/trae/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/vscode/references/extraction-spec.md b/graphify/skills/vscode/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/vscode/references/extraction-spec.md +++ b/graphify/skills/vscode/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/graphify/skills/windows/references/extraction-spec.md b/graphify/skills/windows/references/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/graphify/skills/windows/references/extraction-spec.md +++ b/graphify/skills/windows/references/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tests/test_scoped_ast_inventory.py b/tests/test_scoped_ast_inventory.py new file mode 100644 index 0000000000..8b62cf5f7b --- /dev/null +++ b/tests/test_scoped_ast_inventory.py @@ -0,0 +1,334 @@ +"""Tests for scoped AST symbol inventory generation and integration (Issue #3253).""" +from pathlib import Path +import pytest +from graphify.extract import scope_ast_inventory +from graphify.build import build_from_json +def test_path_matching(): + """Document mentioning graphify/auth/session.py selects symbols from that file.""" + ast_data = { + "nodes": [ + {"id": "graphify_auth_session_py", "label": "session.py", "source_file": "graphify/auth/session.py"}, + {"id": "graphify_auth_session_sessionmanager", "label": "SessionManager", "source_file": "graphify/auth/session.py"}, + {"id": "other_file_foo", "label": "Foo", "source_file": "other/file.py"}, + ], + "edges": [ + {"source": "graphify_auth_session_py", "target": "graphify_auth_session_sessionmanager", "relation": "contains"}, + ], + } + doc_text = "See graphify/auth/session.py for authentication handling." + result = scope_ast_inventory(ast_data, ["docs/auth.md"], [doc_text]) + assert "graphify_auth_session_sessionmanager | SessionManager | graphify/auth/session.py" in result + assert "graphify_auth_session_py | session.py | graphify/auth/session.py" in result + assert "other_file_foo" not in result +def test_unique_basename(): + """Document mentioning unique basename session.py selects the file and its symbols.""" + ast_data = { + "nodes": [ + {"id": "src_auth_session_py", "label": "session.py", "source_file": "src/auth/session.py"}, + {"id": "src_auth_session_token", "label": "Token", "source_file": "src/auth/session.py"}, + {"id": "src_other_worker_py", "label": "worker.py", "source_file": "src/other/worker.py"}, + ], + "edges": [], + } + doc_text = "Refer to session.py for token details." + result = scope_ast_inventory(ast_data, ["docs/spec.md"], [doc_text]) + assert "src_auth_session_token | Token | src/auth/session.py" in result + assert "src_other_worker_py" not in result +def test_ambiguous_basename(): + """Ambiguous basenames (e.g. index.ts, session.py in multiple dirs) are NOT selected by bare basename.""" + ast_data = { + "nodes": [ + {"id": "src_a_session_py", "label": "session.py", "source_file": "src/a/session.py"}, + {"id": "src_a_session_foo", "label": "FooA", "source_file": "src/a/session.py"}, + {"id": "src_b_session_py", "label": "session.py", "source_file": "src/b/session.py"}, + {"id": "src_b_session_bar", "label": "BarB", "source_file": "src/b/session.py"}, + ], + "edges": [], + } + # Bare basename "session.py" is ambiguous + doc_text = "Refer to session.py for details." + result = scope_ast_inventory(ast_data, ["docs/spec.md"], [doc_text]) + assert result == "None available" + # Specific path matches the correct one + doc_text_specific = "Refer to src/a/session.py for details." + result_specific = scope_ast_inventory(ast_data, ["docs/spec.md"], [doc_text_specific]) + assert "src_a_session_foo | FooA | src/a/session.py" in result_specific + assert "src_b_session_bar" not in result_specific +def test_distinctive_identifier_matching(): + """Distinctive identifier like ValidateToken matches its AST node.""" + ast_data = { + "nodes": [ + {"id": "src_auth_session_py", "label": "session.py", "source_file": "src/auth/session.py"}, + {"id": "src_auth_session_validatetoken", "label": "ValidateToken()", "source_file": "src/auth/session.py"}, + {"id": "src_other_unrelated", "label": "UnrelatedHelper()", "source_file": "src/other.py"}, + ], + "edges": [], + } + doc_text = "Clients must call ValidateToken before making API requests." + result = scope_ast_inventory(ast_data, ["docs/api.md"], [doc_text]) + assert "src_auth_session_validatetoken | ValidateToken() | src/auth/session.py" in result + assert "unrelated" not in result.lower() +def test_generic_identifier_filtering(): + """Generic identifiers (run, test, parse, data, get, set) do not match every symbol.""" + ast_data = { + "nodes": [ + {"id": "pkg_a_run", "label": "run()", "source_file": "pkg/a.py"}, + {"id": "pkg_b_run", "label": "run()", "source_file": "pkg/b.py"}, + {"id": "pkg_c_main", "label": "main()", "source_file": "pkg/c.py"}, + ], + "edges": [], + } + doc_text = "Please run the test suite and check the main data pipeline." + result = scope_ast_inventory(ast_data, ["docs/guide.md"], [doc_text]) + assert result == "None available" +def test_class_containment_expansion(): + """Mentioning a class expands to its contained methods.""" + ast_data = { + "nodes": [ + {"id": "src_auth_sessionmanager", "label": "SessionManager", "source_file": "src/auth.py"}, + {"id": "src_auth_sessionmanager_validate", "label": ".validate()", "source_file": "src/auth.py"}, + {"id": "src_auth_sessionmanager_logout", "label": ".logout()", "source_file": "src/auth.py"}, + {"id": "src_other_unrelated", "label": "OtherClass", "source_file": "src/other.py"}, + ], + "edges": [ + {"source": "src_auth_sessionmanager", "target": "src_auth_sessionmanager_validate", "relation": "method"}, + {"source": "src_auth_sessionmanager", "target": "src_auth_sessionmanager_logout", "relation": "method"}, + ], + } + doc_text = "The SessionManager coordinates user lifecycle." + result = scope_ast_inventory(ast_data, ["docs/arch.md"], [doc_text]) + assert "src_auth_sessionmanager | SessionManager | src/auth.py" in result + assert "src_auth_sessionmanager_validate | SessionManager.validate() | src/auth.py" in result + assert "src_auth_sessionmanager_logout | SessionManager.logout() | src/auth.py" in result + assert "OtherClass" not in result +def test_same_file_duplicate_methods_qualified_names(): + """Methods with identical base labels in the same file get disambiguated qualified names.""" + ast_data = { + "nodes": [ + {"id": "src_service_py", "label": "service.ts", "source_file": "src/service.ts"}, + {"id": "src_service_authservice", "label": "AuthService", "source_file": "src/service.ts"}, + {"id": "src_service_authservice_run", "label": ".run()", "source_file": "src/service.ts"}, + {"id": "src_service_billingservice", "label": "BillingService", "source_file": "src/service.ts"}, + {"id": "src_service_billingservice_run", "label": ".run()", "source_file": "src/service.ts"}, + ], + "edges": [ + {"source": "src_service_authservice", "target": "src_service_authservice_run", "relation": "method"}, + {"source": "src_service_billingservice", "target": "src_service_billingservice_run", "relation": "method"}, + ], + } + doc_text = "Both AuthService and BillingService are service workers." + result = scope_ast_inventory(ast_data, ["docs/services.md"], [doc_text]) + assert "src_service_authservice_run | AuthService.run() | src/service.ts" in result + assert "src_service_billingservice_run | BillingService.run() | src/service.ts" in result +def test_file_nodes_included(): + """File node is included when a file or its symbols are referenced.""" + ast_data = { + "nodes": [ + {"id": "graphify_extract_py", "label": "extract.py", "source_file": "graphify/extract.py"}, + {"id": "graphify_extract_extract", "label": "extract()", "source_file": "graphify/extract.py"}, + ], + "edges": [ + {"source": "graphify_extract_py", "target": "graphify_extract_extract", "relation": "contains"}, + ], + } + doc_text = "The pipeline is implemented in graphify/extract.py." + result = scope_ast_inventory(ast_data, ["docs/overview.md"], [doc_text]) + assert "graphify_extract_py | extract.py | graphify/extract.py" in result + assert "graphify_extract_extract | extract() | graphify/extract.py" in result +def test_no_matches_empty_behavior(): + """Pure conceptual doc with no code references returns 'None available'.""" + ast_data = { + "nodes": [ + {"id": "src_code_a", "label": "SomeFunction()", "source_file": "src/code.py"}, + ], + "edges": [], + } + doc_text = "This whitepaper describes the philosophical foundations of graph structures." + result = scope_ast_inventory(ast_data, ["docs/whitepaper.md"], [doc_text]) + assert result == "None available" +def test_deterministic_ordering(): + """Scoping produces byte-stable deterministic output across multiple invocations.""" + ast_data = { + "nodes": [ + {"id": "z_node", "label": "ZetaClass", "source_file": "src/z.py"}, + {"id": "a_node", "label": "AlphaClass", "source_file": "src/a.py"}, + {"id": "m_node", "label": "BetaClass", "source_file": "src/m.py"}, + ], + "edges": [], + } + doc_text = "Mentioning ZetaClass, AlphaClass, and BetaClass together." + res1 = scope_ast_inventory(ast_data, ["docs/doc.md"], [doc_text]) + res2 = scope_ast_inventory(ast_data, ["docs/doc.md"], [doc_text]) + assert res1 == res2 + # Verify order is by source_file: src/a.py -> src/m.py -> src/z.py + lines = res1.splitlines() + assert "src/a.py" in lines[0] + assert "src/m.py" in lines[1] + assert "src/z.py" in lines[2] +def test_hard_cap_100(): + """When more than 100 symbols match, candidate set is deterministically capped at 100.""" + nodes = [] + for i in range(150): + nodes.append({ + "id": f"src_mod_{i:03d}_symbol", + "label": f"CustomSymbol{i:03d}", + "source_file": f"src/mod_{i:03d}.py", + }) + ast_data = {"nodes": nodes, "edges": []} + doc_text = " ".join([f"CustomSymbol{i:03d}" for i in range(150)]) + result = scope_ast_inventory(ast_data, ["docs/all.md"], [doc_text], max_symbols=100) + lines = result.splitlines() + assert len(lines) == 100 + assert "CustomSymbol000" in lines[0] + assert "CustomSymbol099" in lines[99] +def test_canonical_edge_survives_build_from_json(): + """Integration: An edge targeting a canonical AST node ID survives build_from_json without ghosting.""" + ast_nodes = [ + {"id": "src_auth_session_validatetoken", "label": "ValidateToken()", "file_type": "code", "source_file": "src/auth/session.py"}, + ] + sem_nodes = [ + {"id": "docs_architecture_authoverview", "label": "AuthOverview", "file_type": "document", "source_file": "docs/architecture.md"}, + ] + sem_edges = [ + { + "source": "docs_architecture_authoverview", + "target": "src_auth_session_validatetoken", + "relation": "references", + "confidence": "EXTRACTED", + "confidence_score": 1.0, + "source_file": "docs/architecture.md", + } + ] + combined_data = { + "nodes": ast_nodes + sem_nodes, + "edges": sem_edges, + } + g = build_from_json(combined_data) + assert "src_auth_session_validatetoken" in g + assert "docs_architecture_authoverview" in g + assert g.has_edge("docs_architecture_authoverview", "src_auth_session_validatetoken") + edge_data = g.get_edge_data("docs_architecture_authoverview", "src_auth_session_validatetoken") + assert edge_data["relation"] == "references" +def test_windows_path_normalization(): + """Windows backslash paths in AST nodes are normalized to POSIX in the scoped output.""" + ast_data = { + "nodes": [ + {"id": "src_auth_session_py", "label": "session.py", "source_file": "src\\auth\\session.py"}, + {"id": "src_auth_session_token", "label": "Token", "source_file": "src\\auth\\session.py"}, + ], + "edges": [], + } + doc_text = "See src/auth/session.py for details regarding Token." + result = scope_ast_inventory(ast_data, ["docs/spec.md"], [doc_text]) + assert "src/auth/session.py" in result + assert "\\" not in result + assert "src_auth_session_token | Token | src/auth/session.py" in result + assert "src_auth_session_py | session.py | src/auth/session.py" in result +def test_extraction_system_prompt_formatting(): + """_extraction_system injects CODE_SYMBOLS block when provided, omits when None/empty.""" + from graphify.llm import _extraction_system + prompt_none = _extraction_system(code_symbols=None) + assert "Code Symbol Inventory" not in prompt_none + prompt_empty = _extraction_system(code_symbols="None available") + assert "Code Symbol Inventory" not in prompt_empty + symbols = "src_auth_session_validatetoken | ValidateToken() | src/auth/session.py" + prompt_with_symbols = _extraction_system(code_symbols=symbols) + assert "Code Symbol Inventory (canonical code symbols available for this chunk):" in prompt_with_symbols + assert symbols in prompt_with_symbols + assert "Do NOT create a duplicate file_type=\"code\" node" in prompt_with_symbols +def test_deep_nested_qualified_names(): + """Multi-level class nesting (Outer -> Inner -> method()) produces Outer.Inner.method().""" + ast_data = { + "nodes": [ + {"id": "src_tree_py", "label": "tree.py", "source_file": "src/tree.py"}, + {"id": "src_tree_outer", "label": "Outer", "source_file": "src/tree.py"}, + {"id": "src_tree_inner", "label": "Inner", "source_file": "src/tree.py"}, + {"id": "src_tree_method", "label": ".run()", "source_file": "src/tree.py"}, + ], + "edges": [ + {"source": "src_tree_py", "target": "src_tree_outer", "relation": "contains"}, + {"source": "src_tree_outer", "target": "src_tree_inner", "relation": "contains"}, + {"source": "src_tree_inner", "target": "src_tree_method", "relation": "method"}, + ], + } + doc_text = "The Outer container wraps Inner." + result = scope_ast_inventory(ast_data, ["docs/tree.md"], [doc_text]) + assert "src_tree_method | Outer.Inner.run() | src/tree.py" in result + assert "src_tree_inner | Outer.Inner | src/tree.py" in result + assert "src_tree_outer | Outer | src/tree.py" in result +def test_nested_function_containment(): + """Multi-level function nesting (OuterFunction -> InnerFunction -> DeepFunction) reflects the containment chain.""" + ast_data = { + "nodes": [ + {"id": "src_funcs_py", "label": "funcs.py", "source_file": "src/funcs.py"}, + {"id": "src_funcs_outer", "label": "OuterFunction()", "source_file": "src/funcs.py"}, + {"id": "src_funcs_inner", "label": "InnerFunction()", "source_file": "src/funcs.py"}, + {"id": "src_funcs_deep", "label": "DeepFunction()", "source_file": "src/funcs.py"}, + ], + "edges": [ + {"source": "src_funcs_py", "target": "src_funcs_outer", "relation": "contains"}, + {"source": "src_funcs_outer", "target": "src_funcs_inner", "relation": "contains"}, + {"source": "src_funcs_inner", "target": "src_funcs_deep", "relation": "contains"}, + ], + } + doc_text = "See OuterFunction for the nested execution pipeline." + result = scope_ast_inventory(ast_data, ["docs/pipeline.md"], [doc_text]) + assert "src_funcs_deep | OuterFunction.InnerFunction.DeepFunction() | src/funcs.py" in result + assert "src_funcs_inner | OuterFunction.InnerFunction() | src/funcs.py" in result + assert "src_funcs_outer | OuterFunction() | src/funcs.py" in result +def test_backend_prompt_injection(tmp_path, monkeypatch): + """extract_files_direct with ast_data automatically scopes symbols and injects them into system prompt.""" + from graphify.llm import extract_files_direct + doc_file = tmp_path / "spec.md" + doc_file.write_text("Refer to SessionHandler for authentication.", encoding="utf-8") + ast_data = { + "nodes": [ + {"id": "src_auth_py", "label": "auth.py", "source_file": "src/auth.py"}, + {"id": "src_auth_sessionhandler", "label": "SessionHandler", "source_file": "src/auth.py"}, + {"id": "src_auth_sessionhandler_login", "label": ".login()", "source_file": "src/auth.py"}, + ], + "edges": [ + {"source": "src_auth_sessionhandler", "target": "src_auth_sessionhandler_login", "relation": "method"}, + ], + } + captured_kwargs = {} + def mock_call_openai_compat(base_url, api_key, model, user_message, **kwargs): + captured_kwargs.update(kwargs) + return {"nodes": [], "edges": [], "hyperedges": [], "input_tokens": 10, "output_tokens": 10, "model": model} + monkeypatch.setattr("graphify.llm._call_openai_compat", mock_call_openai_compat) + result = extract_files_direct( + [doc_file], + backend="openai", + api_key="sk-test-fake", + ast_data=ast_data, + root=tmp_path, + ) + code_symbols = captured_kwargs.get("code_symbols") + assert code_symbols is not None + assert "src_auth_sessionhandler | SessionHandler | src/auth.py" in code_symbols + assert "src_auth_sessionhandler_login | SessionHandler.login() | src/auth.py" in code_symbols + assert "src_auth_py | auth.py | src/auth.py" in code_symbols +def test_malformed_ast_robustness(): + """scope_ast_inventory handles dangling edges, missing nodes, and cyclic containment without looping or crashing.""" + ast_data = { + "nodes": [ + {"id": "node_a", "label": "AlphaClass", "source_file": "src/alpha.py"}, + {"id": "node_b", "label": "BetaClass", "source_file": "src/alpha.py"}, + ], + "edges": [ + # Cyclic containment + {"source": "node_a", "target": "node_b", "relation": "contains"}, + {"source": "node_b", "target": "node_a", "relation": "contains"}, + # Dangling edges pointing to missing IDs + {"source": "node_a", "target": "nonexistent_child", "relation": "contains"}, + {"source": "nonexistent_parent", "target": "node_a", "relation": "contains"}, + # Malformed edge dict + {"relation": "contains"}, + None, + ], + } + doc_text = "AlphaClass is used here." + result = scope_ast_inventory(ast_data, ["docs/guide.md"], [doc_text]) + assert "node_a" in result + assert "node_b" in result + assert "None available" not in result diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 190827d9ac..7bdf5f242a 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -258,7 +256,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -271,7 +269,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 4996beb787..57fa1c8992 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -179,13 +179,11 @@ This step has two parts: **structural extraction** (deterministic, free) and **s > **graphify needs no API key. Never ask the user for one, and never block on one.** Code is extracted structurally (AST) with no LLM and no key at all — a code-only corpus (the common `/graphify .` on a repo) skips semantic extraction entirely, so go straight to Part A and skip Part B. Semantic extraction (only for docs, papers, and images) is done by your own model. graphify does **not** read `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or any other provider key. If you cannot dispatch subagents, do not stall: a code-only corpus has no semantic work (write the empty semantic file and continue to Part C); for docs/papers/images, extract them inline yourself. If you catch yourself about to prompt for or block on a missing API key, that is a misread of this skill — proceed without one. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 190827d9ac..7bdf5f242a 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -258,7 +256,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -271,7 +269,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index abd2811d23..ed7925cc41 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index af3f723c78..0c916523e5 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -259,7 +257,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Call `spawn_agent` once per chunk — ALL in the same response so they run in parallel. Build the message by wrapping the extraction prompt in task-delegation framing: ``` -spawn_agent(agent_type="worker", message="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +spawn_agent(agent_type="worker", message="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` After all agents are dispatched, collect results sequentially in memory: @@ -271,7 +269,7 @@ Parse each result as JSON. Accumulate nodes/edges/hyperedges across all results Subagent prompt template: -See `references/extraction-spec.md` for the compact subagent prompt (rules, node-ID format, confidence rubric, hyperedge and vision rules, JSON schema). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted, and have it return the JSON inline. +See `references/extraction-spec.md` for the compact subagent prompt (rules, node-ID format, confidence rubric, hyperedge and vision rules, code symbol inventory, JSON schema). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted, and have it return the JSON inline. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index abd2811d23..ed7925cc41 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index f9be846cbf..347bcb2b24 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -192,13 +192,11 @@ This step has two parts: **structural extraction** (deterministic, free) and **s > **graphify needs no API key. Never ask the user for one, and never block on one.** Code is extracted structurally (AST) with no LLM and no key at all — a code-only corpus (the common `/graphify .` on a repo) skips semantic extraction entirely, so go straight to Part A and skip Part B. Semantic extraction (only for docs, papers, and images) is done by your own model. graphify does **not** read `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or any other provider key. If you cannot dispatch subagents, do not stall: a code-only corpus has no semantic work (write the empty semantic file and continue to Part C); for docs/papers/images, extract them inline yourself. If you catch yourself about to prompt for or block on a missing API key, that is a misread of this skill — proceed without one. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index fd148d485d..a72775326a 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -258,7 +256,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -271,7 +269,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index 3e70b050a4..d505f669a7 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index abd2811d23..ed7925cc41 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index 91ced60675..8581c8716f 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -257,7 +255,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Dispatch one `@mention` per chunk — ALL in the same response: ``` -@agent Chunk CHUNK_NUM of TOTAL_CHUNKS: [extraction prompt with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted] +@agent Chunk CHUNK_NUM of TOTAL_CHUNKS: [extraction prompt with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted] @agent Chunk 2 of TOTAL_CHUNKS: [next chunk] ``` @@ -266,7 +264,7 @@ Wait for all agents to return. Parse each response as JSON. Accumulate nodes/edg Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index abd2811d23..ed7925cc41 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 050667bc20..9ab7480262 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -259,7 +257,7 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -272,7 +270,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 20c7c0835c..fad1f906f7 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -270,7 +268,7 @@ Repeat for every chunk. Each chunk's JSON must land in its own `graphify-out/.gr Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted, and write its response to that chunk's file. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted, and write its response to that chunk's file. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index b09ecca3c4..3bd88c41de 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -190,13 +190,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```powershell @' @@ -291,7 +289,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```powershell @@ -301,7 +299,7 @@ $PROJECT_ROOT = (Get-Location).Path # cwd — where Part C globs graphify-out\ Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index abd2811d23..ed7925cc41 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -163,13 +163,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " @@ -264,7 +262,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -274,7 +272,7 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. **Step B3 - Collect, cache, and merge** diff --git a/tools/skillgen/expected/graphify__skills__agents__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__agents__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__amp__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__amp__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__claude__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__claude__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__copilot__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__droid__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__droid__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__kilo__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__opencode__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__trae__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__trae__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__vscode__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/expected/graphify__skills__windows__references__extraction-spec.md b/tools/skillgen/expected/graphify__skills__windows__references__extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__extraction-spec.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 4996beb787..57fa1c8992 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -179,13 +179,11 @@ This step has two parts: **structural extraction** (deterministic, free) and **s > **graphify needs no API key. Never ask the user for one, and never block on one.** Code is extracted structurally (AST) with no LLM and no key at all — a code-only corpus (the common `/graphify .` on a repo) skips semantic extraction entirely, so go straight to Part A and skip Part B. Semantic extraction (only for docs, papers, and images) is done by your own model. graphify does **not** read `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or any other provider key. If you cannot dispatch subagents, do not stall: a code-only corpus has no semantic work (write the empty semantic file and continue to Part C); for docs/papers/images, extract them inline yourself. If you catch yourself about to prompt for or block on a missing API key, that is a misread of this skill — proceed without one. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index c527a12563..3a4ac2866d 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -122,13 +122,11 @@ Print it once, then continue — do not wait for the user to supply a key. If `G > **No other API keys are read.** When `GEMINI_API_KEY`/`GOOGLE_API_KEY` are unset, semantic extraction falls to the host agent itself — the running session is the LLM. On a host that dispatches subagents (e.g. Claude Code), dispatch them as written in Part B. On a host that runs the CLI directly in a terminal and cannot dispatch subagents, do not stall: a code-only corpus has no semantic work, so write the empty semantic file (Part B "Fast path") and continue to Part C; for a corpus with docs/papers/images, either set a Gemini key or extract those inline yourself, but in no case prompt for `ANTHROPIC_API_KEY` — that prompt is a misread of this skill. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index f9be846cbf..347bcb2b24 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -192,13 +192,11 @@ This step has two parts: **structural extraction** (deterministic, free) and **s > **graphify needs no API key. Never ask the user for one, and never block on one.** Code is extracted structurally (AST) with no LLM and no key at all — a code-only corpus (the common `/graphify .` on a repo) skips semantic extraction entirely, so go straight to Part A and skip Part B. Semantic extraction (only for docs, papers, and images) is done by your own model. graphify does **not** read `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or any other provider key. If you cannot dispatch subagents, do not stall: a code-only corpus has no semantic work (write the empty semantic file and continue to Part C); for docs/papers/images, extract them inline yourself. If you catch yourself about to prompt for or block on a missing API key, that is a misread of this skill — proceed without one. -**Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** - -Note: Parallelizing AST + semantic saves 5-15s on large corpora. AST is deterministic and fast; start it while subagents are processing docs/papers. +**Run Part A (AST) first so `.graphify_ast.json` is fully written. Step B2 will scope relevant AST symbols from `.graphify_ast.json` into each semantic subagent's prompt, enabling cross-domain document → code references with canonical IDs. Merge results in Part C as before.** #### Part A - Structural extraction for code files -For any code files detected, run AST extraction in parallel with Part B subagents: +For any code files detected, run AST extraction: ```bash $(cat graphify-out/.graphify_python) -c " diff --git a/tools/skillgen/fragments/dispatch/agent-tool-disk-powershell.md b/tools/skillgen/fragments/dispatch/agent-tool-disk-powershell.md index 54f2f54e3d..9cc7f6bb11 100644 --- a/tools/skillgen/fragments/dispatch/agent-tool-disk-powershell.md +++ b/tools/skillgen/fragments/dispatch/agent-tool-disk-powershell.md @@ -12,7 +12,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```powershell @@ -22,4 +22,4 @@ $PROJECT_ROOT = (Get-Location).Path # cwd — where Part C globs graphify-out\ Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. diff --git a/tools/skillgen/fragments/dispatch/agent-tool-disk.md b/tools/skillgen/fragments/dispatch/agent-tool-disk.md index 9e07ca5db3..2433041f66 100644 --- a/tools/skillgen/fragments/dispatch/agent-tool-disk.md +++ b/tools/skillgen/fragments/dispatch/agent-tool-disk.md @@ -12,7 +12,7 @@ Concrete example for 3 chunks: ``` All three in one message. Not three separate messages. -Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). CHUNK_PATH must be an **absolute** path — derive it before dispatching: ```bash @@ -22,4 +22,4 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. diff --git a/tools/skillgen/fragments/dispatch/codex-agenttask.md b/tools/skillgen/fragments/dispatch/codex-agenttask.md index 1fd2f6a1a7..e9eaf02c5d 100644 --- a/tools/skillgen/fragments/dispatch/codex-agenttask.md +++ b/tools/skillgen/fragments/dispatch/codex-agenttask.md @@ -7,7 +7,7 @@ Call `spawn_agent` once per chunk — ALL in the same response so they run in parallel. Build the message by wrapping the extraction prompt in task-delegation framing: ``` -spawn_agent(agent_type="worker", message="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +spawn_agent(agent_type="worker", message="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` After all agents are dispatched, collect results sequentially in memory: @@ -19,4 +19,4 @@ Parse each result as JSON. Accumulate nodes/edges/hyperedges across all results Subagent prompt template: -See `references/extraction-spec.md` for the compact subagent prompt (rules, node-ID format, confidence rubric, hyperedge and vision rules, JSON schema). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted, and have it return the JSON inline. +See `references/extraction-spec.md` for the compact subagent prompt (rules, node-ID format, confidence rubric, hyperedge and vision rules, code symbol inventory, JSON schema). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted, and have it return the JSON inline. diff --git a/tools/skillgen/fragments/dispatch/manual-paste.md b/tools/skillgen/fragments/dispatch/manual-paste.md index b4120cc301..0618a68758 100644 --- a/tools/skillgen/fragments/dispatch/manual-paste.md +++ b/tools/skillgen/fragments/dispatch/manual-paste.md @@ -18,4 +18,4 @@ Repeat for every chunk. Each chunk's JSON must land in its own `graphify-out/.gr Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted, and write its response to that chunk's file. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted, and write its response to that chunk's file. diff --git a/tools/skillgen/fragments/dispatch/opencode-mention.md b/tools/skillgen/fragments/dispatch/opencode-mention.md index f87f5fb51b..1d8ba00eb3 100644 --- a/tools/skillgen/fragments/dispatch/opencode-mention.md +++ b/tools/skillgen/fragments/dispatch/opencode-mention.md @@ -5,7 +5,7 @@ Dispatch one `@mention` per chunk — ALL in the same response: ``` -@agent Chunk CHUNK_NUM of TOTAL_CHUNKS: [extraction prompt with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted] +@agent Chunk CHUNK_NUM of TOTAL_CHUNKS: [extraction prompt with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted] @agent Chunk 2 of TOTAL_CHUNKS: [next chunk] ``` @@ -14,4 +14,4 @@ Wait for all agents to return. Parse each response as JSON. Accumulate nodes/edg Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE substituted. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each agent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CODE_SYMBOLS substituted. diff --git a/tools/skillgen/fragments/dispatch/task-tool-disk-trae.md b/tools/skillgen/fragments/dispatch/task-tool-disk-trae.md index 5ee3a4a62f..b39613434a 100644 --- a/tools/skillgen/fragments/dispatch/task-tool-disk-trae.md +++ b/tools/skillgen/fragments/dispatch/task-tool-disk-trae.md @@ -7,7 +7,7 @@ Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -20,4 +20,4 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. diff --git a/tools/skillgen/fragments/dispatch/task-tool-disk.md b/tools/skillgen/fragments/dispatch/task-tool-disk.md index d3c9caae6e..8a2ab8446a 100644 --- a/tools/skillgen/fragments/dispatch/task-tool-disk.md +++ b/tools/skillgen/fragments/dispatch/task-tool-disk.md @@ -6,7 +6,7 @@ Pass the extraction prompt as the task description: ``` -Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") +Task(description="Your task is to perform the following. Follow the instructions below exactly.\n\n\n[extraction prompt, with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CODE_SYMBOLS substituted]\n\n\nExecute this now. Output ONLY the structured JSON response.") ``` Each subagent writes its result to its own `graphify-out/.graphify_chunk_NN.json`. Collect results as each `Task` completes and parse each as JSON. @@ -19,4 +19,4 @@ PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_r Subagent prompt template: -See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH. +See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, hyperedge, vision rules, and code symbol inventory). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS substituted, and have it write the result to CHUNK_PATH. diff --git a/tools/skillgen/fragments/references/shared/extraction-spec.md b/tools/skillgen/fragments/references/shared/extraction-spec.md index 388df7674f..4280ac5ab3 100644 --- a/tools/skillgen/fragments/references/shared/extraction-spec.md +++ b/tools/skillgen/fragments/references/shared/extraction-spec.md @@ -1,6 +1,6 @@ # graphify reference: extraction subagent prompt -Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH). +Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, CHUNK_PATH, and CODE_SYMBOLS). ``` You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. @@ -60,6 +60,14 @@ confidence_score is REQUIRED on every edge - never omit it, never use 0.5 as a d Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format: `{stem}_{entity}` where stem is the **full repo-relative path with the extension dropped**, every path segment kept and joined with `_` (each segment lowercased with non-alphanumeric chars replaced by `_`), and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent — this keeps same-named files in different directories distinct. Examples: `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`; `lib/utils/helpers.py` + `parse_url` → `lib_utils_helpers_parse_url`; `tests/test_foo.py` + `_helper` → `tests_test_foo_helper`; `docs/v1/api/README.md` + `getUser` → `docs_v1_api_readme_getuser`. Top-level files (no parent dir, e.g. `setup.py`) use just the filename stem: `setup_my_func`. This must match the ID the AST extractor generates — using just the filename (e.g., `session_validatetoken`) or only the immediate parent (e.g., `auth_session_validatetoken`) will create orphan ghost-duplicate nodes. If you are re-extracting a project built under the old immediate-parent format, the user should run `graphify extract --force` to rebuild cleanly. CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no `_c1`, `_c2`, `_chunk2`, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it. +Code Symbol Inventory (canonical code symbols available for this chunk): +CODE_SYMBOLS + +Rules for Code References: +- When a document or paper references, describes, or implements an existing code component, use the exact canonical `id` from the Code Symbol Inventory above as the edge `target`. +- Do NOT invent a different ID for an inventory entry. +- Do NOT create a duplicate `file_type: "code"` node for a symbol that already exists in the inventory. Emit the edge directly to the canonical AST node ID. + Generate the extraction JSON matching this schema exactly: {"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":""}],"input_tokens":0,"output_tokens":0} diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 09e19ede00..5a451c74f9 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1142,6 +1142,21 @@ def _is_community_label_export_fix_line(line: str) -> bool: ) +def _is_ast_first_execution_order_fix_line(line: str) -> bool: + """Whether a line is part of the Step 3 Part A AST-first execution order (#3253). + + Part A must run first so .graphify_ast.json is written before semantic subagents + are dispatched with a scoped CODE_SYMBOLS inventory. + """ + return ( + "Run Part A (AST) first so `.graphify_ast.json` is fully written" in line + or "Run Part A (AST) and Part B (semantic) in parallel" in line + or "Parallelizing AST + semantic saves" in line + or "run AST extraction in parallel with Part B subagents" in line + or line.strip() == "For any code files detected, run AST extraction:" + ) + + # 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 +1178,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_ast_first_execution_order_fix_line, )