graphify VS Code /graphify 技能剧本详解:九步流水线、manual-paste 派发与图构建守护机制
graphify 把任意目录的代码、文档、论文、图片、视频编译成一张可查询的知识图谱,并在构建全程保留 EXTRACTED / INFERRED / AMBIGUOUS 三级诚实审计链。skill-vscode.md 是该工具面向 VS Code 宿主 Agent 的完整技能剧本(skill playbook):它规定了 /graphify 命令的全部用法、从解释器探测到图谱导出的九步流水线,以及查询、增量更新与提交钩子的执行细则。读完本文,你可以完整复述 graphify 的构建流程与缓存策略,理解为什么纯代码语料不需要 API key,并掌握 shrink-guard、manifest 盖章等防止图谱静默损坏的关键设计。
这是什么文件:VS Code 宿主的生成产物
skill-vscode.md 不是手写的普通文档,而是 skillgen 构建工具渲染出的提交型产物。仓库中的 platforms.toml 声明了 vscode 平台的装配方式:
bucket = "split":采用"精简核心 + references 侧车"的结构,核心正文渲染为 skill-vscode.md,配套参考资料渲染到 skills/vscode/references/ 目录(add-watch、exports、extraction-spec、github-and-merge、hooks、query、transcribe、update 共 8 个文件);dispatch = "manual-paste":VS Code 宿主没有并行 Agent/Task API,语义抽取子代理由人手动派发并粘贴结果——这正是正文 Step B2 中那段 "No automated subagent tool" 注释的来源(对应片段 manual-paste.md);extraction = "verbose":使用详细版抽取规范。
生成器 gen.py 支持 --check(字节级漂移检测)与 --bless(刷新期望产物),保证所有宿主平台的技能文件与源片段保持一致。
Usage:/graphify 命令全量参考
剧本开头的 ## Usage 块是 /graphify --help 的逐字输出内容,也是整个技能的入口契约。完整命令面如下(原文档第 12–43 行):
/graphify # full pipeline on current directory (HTML viz; add --obsidian for a vault)
/graphify <path> # full pipeline on specific path
/graphify https://github.com/<owner>/<repo> # clone repo then run full pipeline on it
/graphify https://github.com/<owner>/<repo> --branch <branch> # clone a specific branch
/graphify <url1> <url2> ... # clone multiple repos, build each, merge into one cross-repo graph
/graphify <path> --mode deep # thorough extraction, richer INFERRED edges
/graphify <path> --update # incremental - re-extract only new/changed files
/graphify <path> --directed # build directed graph (preserves edge direction: source→target)
/graphify <path> --whisper-model medium # use a larger Whisper model for better transcription accuracy
/graphify <path> --cluster-only # rerun clustering on existing graph
/graphify <path> --no-viz # skip visualization, just report + JSON
/graphify <path> --html # (HTML is generated by default - this flag is a no-op)
/graphify <path> --svg # also export graph.svg (embeds in Notion, GitHub)
/graphify <path> --graphml # export graph.graphml (Gephi, yEd)
/graphify <path> --neo4j # generate graphify-out/cypher.txt for Neo4j
/graphify <path> --neo4j-push bolt://localhost:7687 # push directly to Neo4j
/graphify <path> --falkordb # generate graphify-out/cypher.txt for FalkorDB
/graphify <path> --falkordb-push falkordb://localhost:6379 # push directly to FalkorDB
/graphify <path> --mcp # start MCP stdio server for agent access
/graphify <path> --watch # watch folder, auto-rebuild on code changes (no LLM needed)
/graphify <path> --wiki # build agent-crawlable wiki (index.md + one article per community)
/graphify <path> --obsidian --obsidian-dir ~/vaults/my-project # write vault to custom path (e.g. existing vault)
/graphify add <url> # fetch URL, save to ./raw, update graph
/graphify add <url> --author "Name" # tag who wrote it
/graphify add <url> --contributor "Name" # tag who added it to the corpus
/graphify query "<question>" # BFS traversal - broad context
/graphify query "<question>" --dfs # DFS - trace a specific path
/graphify query "<question>" --budget 1500 # cap answer at N tokens
/graphify path "AuthModule" "Database" # shortest path between two concepts
/graphify explain "SwinTransformer" # plain-language explanation of a node
按功能分组理解:
| 类别 | 命令/参数 | 说明 |
|---|---|---|
| 构建范围 | 无参 / <path> / GitHub URL / 多 URL |
默认对当前目录做完整流水线;URL 触发 Step 0 克隆(多 URL 会合并为一张跨仓库图) |
| 抽取模式 | --mode deep、--whisper-model |
深度抽取产生更丰富的 INFERRED 边;更大的 Whisper 模型提升转写准确率 |
| 增量 | --update、--cluster-only |
只重抽新增/变更文件;仅在已有图上重跑社区发现 |
| 图形态 | --directed |
构建 DiGraph 保留 source→target 方向,否则默认无向 Graph |
| 导出 | --svg --graphml --neo4j(-push) --falkordb(-push) --wiki --mcp |
对应 cli.py 中的 export 子命令 html/callflow-html/obsidian/wiki/svg/graphml/neo4j/falkordb;push 变体直接写入图数据库 |
| 可视化 | --no-viz、--html、--obsidian [--obsidian-dir <path>] |
HTML 默认生成(--html 是 no-op);--obsidian 显式开启才逐节点生成 vault 文件 |
| 运维 | --watch、add |
监听目录自动重建(无需 LLM);抓取 URL 进语料并更新图 |
| 查询 | query(--dfs、--budget N)、path、explain |
BFS 广域上下文 / DFS 路径追踪 / 节点白话解释 |
快速路径:先查已有图,而不是重建
剧本在"必须执行的动作"里定义了一条快速路径:执行任何检测之前,先检查 graphify-out/graph.json(相对于当前工作目录,即项目根)是否存在。若存在、且用户请求是关于代码库的自然语言问题("How does X work?"、"What calls Y?"),而不是显式重建命令(--update、--cluster-only 或裸路径/URL):
- 跳过 Step 1–5,直接进入查询流程;
- 立即执行
graphify query "<question>"; - 不跑 detect、不检查语料规模、不要求用户缩小范围——"The graph is already built — use it."
未给路径时默认用 .,不得反问用户;路径若以 https://github.com/ 开头则先走 Step 0 克隆再解析为本地路径。查询侧要求先把问题对图谱自身词表做展开(vocab expansion),避免措辞不匹配导致答案退化成噪声;回答只能基于图输出,引用具体事实时要引用 source_location。遍历模式、--budget 上限、NetworkX 内联兜底、save-result 反馈与 path/explain 流程,完整定义在 query.md 中。
Step 0–2:GitHub 克隆、解释器自举与语料检测
Step 0 仅对 URL / 多路径生效
只有当输入是一个或多个 https://github.com/... URL,或需要合并的多个本地子目录时才执行克隆与跨仓库合并,细则见 github-and-merge.md;纯本地路径直接跳过。
Step 1 解释器探测与安装
这是整份剧本里最长的一段 shell 逻辑,目的是在 uv tool、pipx、venv、系统安装四种安装形态下找到能 import graphify 的解释器,并按优先级尝试:uv tool run --from graphifyy → 读 graphify 二进制的 shebang(带字符集校验)→ 回退 python3。导入失败则 uv tool install --upgrade graphifyy 或 pip install graphifyy(必要时 --break-system-packages)。最后写两个持久化侧车:
graphify-out/.graphify_python:解释器绝对路径,后续所有 bash 块都必须用$(cat graphify-out/.graphify_python)替换python3;graphify-out/.graphify_root:扫描根绝对路径,供无参graphify update定位上次扫描目录。
Step 2 用 detect() 生成检测 JSON,并执行三道规模闸门
$(cat graphify-out/.graphify_python) -c "
import json
from graphify.detect import detect
from pathlib import Path
result = detect(Path('INPUT_PATH'))
# Write the sidecar from Python, not a shell redirect, so the same block renders
# on PowerShell hosts without console-encoding drift (#2528).
Path('graphify-out/.graphify_detect.json').write_text(json.dumps(result, ensure_ascii=False), encoding=\"utf-8\")
print(f'Detected {result[\"total_files\"]} files')
"
实现落点在 detect.py 的 detect()(支持 gitignore 感知、符号链接策略、Google Workspace 等参数)。检测 JSON 由 Python 写入而非 shell 重定向,是为 PowerShell 宿主避免控制台编码漂移(#2528)。
脚本要求静默读取 JSON 并呈现干净摘要(0 文件类别省略):
Corpus: X files · ~Y words
code: N files (.py .ts .go ...)
docs: N files (.md .txt ...)
papers: N files (.pdf ...)
images: N files
video: N files (.mp4 .mp3 ...)
随后按结果行动,这里有三道闸门:
total_files == 0:停止,输出 "No supported files found in [path].";skipped_sensitive非空:报告数量与文件名,让被误判为敏感(凭据)的源文件可见、可改名(#2106);total_words > 2,000,000或total_files > 500:展示警告,然后按 detect JSON 中的scan_root(解析后 INPUT_PATH 的绝对路径),把code/document/paper/image/video全部文件列表拼接、剔除scan_root + "/graphify-out/"前缀的转换产物,按第一级子目录计数排序,展示 top 5 并等待用户选择再继续;若全部文件都在(root)无子目录,则改为建议--no-cluster跳过昂贵的聚类步骤。
测试覆盖见 test_detect.py。
Step 2.5 音视频转写
仅当 detect 返回的 video 数量大于 0 时执行:按 transcribe.md 先把音视频转写成文本,再当作 document 进入 Step 3。零视频文件则整步跳过。
Step 3:AST 与语义抽取并行,代码语料零 API key
这一步分为结构化抽取(确定性、免费)与语义抽取(LLM、耗 token)两部分,剧本明确要求二者并行派发(可省 5–15 秒),在 Part C 汇合。
零 API key 原则
这是剧本中反复强调的契约:graphify 不需要 API key,绝不允许 Agent 向用户索要或被 key 阻塞。代码走 AST 抽取,完全不需要 LLM;纯代码语料(最常见的 /graphify .)会整体跳过 Part B。语义抽取仅在已设置 GEMINI_API_KEY/GOOGLE_API_KEY 时使用 Gemini(graphify.llm.extract_corpus_parallel(files, backend="gemini"),默认模型 gemini-3-flash-preview,可用 GRAPHIFY_GEMINI_MODEL 或 --model 覆盖,扩展安装为 pip install 'graphifyy[gemini]');否则宿主 Agent 本身就是 LLM。graphify 明确不读取 ANTHROPIC_API_KEY、OPENAI_API_KEY 或其他供应商 key——脚本原文直言:如果你发现自己正要为缺失的 API key 而提示或停下,"that is a misread of this skill"。
Part A:AST 结构化抽取
$(cat graphify-out/.graphify_python) -c "
import sys, json
from graphify.extract import collect_files, extract
from pathlib import Path
import json
code_files = []
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding=\"utf-8\"))
for f in detect.get('files', {}).get('code', []):
code_files.extend(collect_files(Path(f)) if Path(f).is_dir() else [Path(f)])
if code_files:
result = extract(code_files, cache_root=Path('INPUT_PATH'))
Path('graphify-out/.graphify_ast.json').write_text(json.dumps(result, indent=2, ensure_ascii=False), encoding=\"utf-8\")
print(f'AST: {len(result[\"nodes\"])} nodes, {len(result[\"edges\"])} edges')
else:
Path('graphify-out/.graphify_ast.json').write_text(json.dumps({'nodes':[],'edges':[],'input_tokens':0,'output_tokens':0}, ensure_ascii=False), encoding=\"utf-8\")
print('No code files - skipping AST extraction')
"
实现落点为 extract.py 的 extract() 与 extract.py 的 collect_files();cache_root 指定后抽取结果参与文件级缓存。
Part B:语义抽取(缓存 → 分块 → 派发 → 收集)
快速路径:若 document/paper/image 均为 0(纯代码语料),必须先写出空语义文件再进 Part C——因为 Part C 无条件读取 .graphify_semantic.json,缺文件会 FileNotFoundError:
$(cat graphify-out/.graphify_python) -c "
import json
from pathlib import Path
Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8')
"
Step B0 先查抽取缓存。只有内容文件进入语义通道——代码已被 Part A 的 AST 覆盖,把每类文件都扁平化进语义通道会让子代理重读所有源码(#1392);视频则已在 Step 2.5 转写为文档:
$(cat graphify-out/.graphify_python) -c "
import json
from graphify.cache import check_semantic_cache
from pathlib import Path
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding=\"utf-8\"))
all_files = [f for cat in ('document', 'paper', 'image') for f in detect['files'].get(cat, [])]
cached_nodes, cached_edges, cached_hyperedges, uncached = check_semantic_cache(all_files, root='INPUT_PATH', prompt_file='SPEC_PATH')
if cached_nodes or cached_edges or cached_hyperedges:
Path('graphify-out/.graphify_cached.json').write_text(json.dumps({'nodes': cached_nodes, 'edges': cached_edges, 'hyperedges': cached_hyperedges}, ensure_ascii=False), encoding=\"utf-8\")
else:
Path('graphify-out/.graphify_cached.json').unlink(missing_ok=True)
Path('graphify-out/.graphify_uncached.txt').write_text('\n'.join(uncached), encoding=\"utf-8\")
print(f'Cache: {len(all_files)-len(uncached)} files hit, {len(uncached)} files need extraction')
"
关键细节:SPEC_PATH 是 extraction-spec.md 的绝对路径,它既是子代理的抽取提示词,也是缓存条目的归属标记——graphify 升级若改动提示词,旧条目会被重新抽取而非重放(#1939)。B0 与 B3 必须传入同一个 SPEC_PATH。缓存实现见 cache.py 的 check_semantic_cache() 与 cache.py 的 save_semantic_cache(),行为由 test_cache.py 覆盖。
Step B1 分块:读取 .graphify_uncached.txt,每块 20–25 个文件;图片单独成块(视觉需要独立上下文);同目录文件尽量聚到同一块以提升跨文件关系命中率。派发前先打印时间估算:ceil(uncached_non_code_files / 22) 个代理、每批约 45 秒,输出 "Semantic extraction: ~N files → X agents, estimated ~Ys"。
Step B2 派发与粘贴(VS Code 特化):剧本对 Claude Code 类宿主要求"必须使用 Agent 工具,逐文件自读慢 5–10 倍";而 VS Code 变体的措辞是——宿主没有并行 Agent/Task API,按宿主允许的方式(新会话、并行分屏)逐块派发,然后把每个响应粘贴回块文件:
# After pasting a subagent's JSON for chunk N, save it (replace N and PASTED_JSON):
PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_root/scan dir, #1392)
cat > "${PROJECT_ROOT}/graphify-out/.graphify_chunk_0N.json" <<'CHUNK_JSON'
PASTED_JSON
CHUNK_JSON
块 JSON 一律落在当前工作目录的 graphify-out/ 下(Part C 在这里做 glob,而非扫描目录,#1392)。子代理提示词本体(JSON schema、节点 ID 规则、置信度评级、hyperedge 与视觉规则)在 extraction-spec.md,仅在至少一个块含 doc/paper/image 时才加载,并需替换 FILE_LIST、CHUNK_NUM、TOTAL_CHUNKS、DEEP_MODE 四个占位符——--mode deep 必须一路透传,不得丢失。
Step B3 收集、缓存与合并:以块文件存在且含合法 nodes/edges JSON 作为成功信号;文件缺失大概率是子代理被以只读(Explore 类型)派发,必须打印警告并要求改用 general-purpose 代理,禁止静默跳过;失败或非法 JSON 的块打印警告后跳过,但超过半数块失败就停止并让用户重跑。合并前还要把 Agent 工具结果 usage 字段里的真实 token 数写回块 JSON(块文件本身恒为占位 0)。随后依次:
- glob
graphify-out/.graphify_chunk_*.json合并出.graphify_semantic_new.json; save_semantic_cache(..., prompt_file='SPEC_PATH')把新结果写入缓存(读旧条目用什么提示词、写新条目就必须用什么提示词,#1939);- 缓存 + 新结果按节点
id去重合并进.graphify_semantic.json,打印Extraction complete - N nodes, M edges (X from cache, Y new); - 清理
.graphify_cached.json、.graphify_uncached.txt、.graphify_semantic_new.json。
Part C:AST + 语义合并
# AST nodes first, semantic nodes deduplicated by id
ast = json.loads(Path('graphify-out/.graphify_ast.json').read_text(encoding=\"utf-8\"))
sem = json.loads(Path('graphify-out/.graphify_semantic.json').read_text(encoding=\"utf-8\"))
seen = {n['id'] for n in ast['nodes']}
merged_nodes = list(ast['nodes'])
for n in sem['nodes']:
if n['id'] not in seen:
merged_nodes.append(n)
seen.add(n['id'])
merged_edges = ast['edges'] + sem['edges']
merged_hyperedges = sem.get('hyperedges', [])
# → graphify-out/.graphify_extract.json
合并顺序体现"确定性优先":AST 节点在前,语义节点按 id 去重补齐;边直接拼接;hyperedges 全部来自语义侧;token 计数继承自语义侧。
Step 4:建图、聚类、分析,以及 shrink-guard
Step 4 之前要替换 IS_DIRECTED(--directed 为 True 构建 DiGraph,否则默认无向 Graph)——和 INPUT_PATH 一样是占位符,不能留字面量进代码。核心块:
G = build_from_json(extraction, root='INPUT_PATH', directed=IS_DIRECTED)
# Guard BEFORE any write: an empty extraction must not clobber a good graph.json /
# GRAPH_REPORT.md / analysis sidecar. Check immediately after build (#1392).
if G.number_of_nodes() == 0:
print('ERROR: Graph is empty - extraction produced no nodes.')
print('Possible causes: all files were skipped, binary-only corpus, or extraction failed.')
raise SystemExit(1)
communities = cluster(G)
cohesion = score_all(G, communities)
gods = god_nodes(G)
surprises = surprising_connections(G, communities)
questions = suggest_questions(G, communities, labels)
wrote = to_json(G, communities, 'graphify-out/graph.json')
if not wrote:
print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).')
print('If this shrink is intentional (you deleted files), re-run a full build with --force.')
raise SystemExit(1)
report = generate(G, communities, cohesion, labels, gods, surprises, detection, tokens, 'INPUT_PATH', suggested_questions=questions)
Path('graphify-out/GRAPH_REPORT.md').write_text(report, encoding=\"utf-8\")
# + graphify-out/.graphify_analysis.json (communities/cohesion/gods/surprises/questions)
这段代码链上每个函数都能在仓库中逐一找到实现与测试:
build_from_json():build.py,root=参数把source_file相对化到与--update相同的基准,保证全量构建与增量更新在重抽时节点 key 不漂移(#1361);cluster()/score_all():cluster.py 与 cluster.py,分别做社区发现与内聚度打分,test_cluster.py 覆盖;god_nodes()/surprising_connections()/suggest_questions():analyze.py、analyze.py、analyze.py,由 test_analyze.py 覆盖;generate():report.py 生成 GRAPH_REPORT.md;to_json():export.py,返回 bool 实现 #479 shrink-guard——新图节点数小于既有 graph.json 时返回 False 且不写盘。剧本要求"先导出、再写报告":只有图真正写入成功,才允许写 GRAPH_REPORT.md 与分析侧车,确保报告永远不会描述一份 graph.json 里没有的图(#1392)。守护行为另有专项测试 test_build_merge_shrink_guard.py。
空图守卫放在任何写盘之前:0 节点直接退出,不污染既有产物。此步打印 ERROR: Graph is empty 时,必须停下并告知用户,禁止继续进入标注或可视化。
Step 4.5–5:只读健康检查与社区标注
Step 4.5 图谱健康检查
一个非破坏性的完整性门,在标注前诊断三类静默损坏——边坍缩、悬空/缺失端点、自环(正是增量更新与 AST/LLM id 失配的典型病灶):
from graphify.diagnostics import diagnose_extraction, format_diagnostic_report
summary = diagnose_extraction(extraction, directed=IS_DIRECTED, root='INPUT_PATH')
print(format_diagnostic_report(summary))
# 汇总 dangling / missing / self-loop / collapsed 边数,打印 GRAPH HEALTH WARNING 或 OK
实现见 diagnostics.py 的 diagnose_extraction() 与 diagnostics.py 的 format_diagnostic_report()。健康检查只读、从不中止:出现 GRAPH HEALTH WARNING 时图仍可用,但依据 Honesty Rules 必须把完整性问题暴露在最终摘要里。
Step 5 为社区写人类可读标签
读取 .graphify_analysis.json,对每个社区的节点标签归纳出 2–5 词的白话名(如 "Attention Mechanism"、"Training Pipeline"),然后重建图、用真实标签重新生成建议问题(标签影响问题措辞)、重写报告、把标签写入 .graphify_labels.json 供可视化器使用,并带 community_labels=labels 重新导出,让 graph.json 的节点携带策展后的 community_name(#2490)。由于与 Step 4 使用同一份 extraction,shrink-guard 按节点数必然通过;若仍被拒绝,把 guard 消息原样呈现,不得 --force 强推。
Step 6 及后续:HTML 恒开、其余导出按需
- HTML 恒开(除非
--no-viz):graphify export html,图超过 5000 节点时自动聚合到社区视图; - Obsidian 仅限显式
--obsidian:graphify export obsidian,可用--dir ~/vaults/my-project写入自定义 vault,因为每节点生成一个文件; - Steps 6b–8(wiki、Neo4j/FalkorDB 生成与 push、SVG、GraphML、MCP、token 压缩基准——后者在
total_words > 5000时触发)仅在其 flag 出现时执行;默认运行全部跳过。逐项说明在 exports.md。注意:--wiki要在 Step 9 清理之前导出,那时.graphify_labels.json尚在。
CLI 侧对应 cli.py 的 export 子命令分派(html、callflow-html、obsidian、wiki、svg、graphml、neo4j、falkordb,neo4j/falkordb 支持 push 与口令环境变量)。
Step 9:manifest 盖章、成本追踪与收尾
收尾步骤完成三件事,核心是 manifest 的选择性盖章:
from graphify.detect import save_manifest
from graphify.cli import _stamped_manifest_files
_corpus = detect.get('all_files') or detect['files']
_manifest_files = _stamped_manifest_files(_corpus, extract, Path('INPUT_PATH'))
# 只给“实际产出了输出”的语义文件盖章;失败/遗漏的块保持未盖,下次 --update 会重新排队(#2015)
# 本运行已派发但未盖章的语义文件清掉旧 semantic_hash,避免被当作未变更(#1948)
save_manifest(_manifest_files, root='INPUT_PATH', scan_corpus=_scan, clear_semantic=_cleared or None)
# → 更新 graphify-out/cost.json 累计 token 成本;打印本次/历史用量
规则要点:
- 代码文件恒盖章(AST 确定性),文档/论文/图片只有真正产出才盖章——被检测到但块失败的文件必须保持未盖章,否则下次
--update会把它当完成态、内容永久丢失(#2015); root=把 manifest key 相对化到扫描根,使磁盘上的 manifest 可跨克隆/机器移植,--update才能命中缓存文件而非全部未命中(#1417);scan_corpus传原始全量语料(而非盖章过滤子集),让根目录内新被排除的文件被正常丢弃而不是伪装成删除,未触碰文件的历史行保留(#1908);cost.json按运行追加{date, input_tokens, output_tokens, files}并累计总量。
最后删除 .graphify_detect/extract/ast/semantic/analysis.json 与所有 .graphify_chunk_*.json、.needs_update,向用户报告产物清单:
Graph complete. Outputs in PATH_TO_DIR/graphify-out/
graph.html - interactive graph, open in browser
GRAPH_REPORT.md - audit report
graph.json - raw graph data
obsidian/ - Obsidian vault (only if --obsidian was given)
随后只粘贴报告中的 God Nodes、Surprising Connections、Suggested Questions 三节(不粘全报告),并主动挑出跨越最多社区边界或桥接节点最出人意味的建议问题,以 "The most interesting question this graph can answer: [question]. Want me to trace it?" 邀请探索。剧本的收束语是:"The graph is the map. Your job after the pipeline is to be the guide."——回答要沿着图结构展开(哪些节点相连、跨越了哪些社区边界、路径揭示了什么),每轮以自然的追问结尾,让会话像导航而非一次性报告。
子命令护栏与增量/查询/追加/监听
解释器护栏:执行 --update、--cluster-only、query、path、explain、add 任何子命令前,先检查 graphify-out/.graphify_python 是否存在;缺失(例如用户删了 graphify-out/)时按 shebang → python3 的顺序重新解析解释器并回写,再运行子命令。
--update/--cluster-only:均为非默认子命令——前者只重抽新增/变更文件,后者在既有图上重跑聚类;两条流程的完整 runbook 在 update.md。增量更新的设计与去重策略另有专项文档 incremental-updates-dedup 设计 与实施计划,测试见 test_incremental.py。/graphify query:图存在时从图回答而不是重建;CLI 不可用时回退到对 graph.json 的内联 NetworkX 遍历。参数与流程详见 query.md 与 test_query_cli.py。/graphify add与--watch:不属于默认构建;URL 抓取与目录监听的完整流程在 add-watch.md。- 提交钩子与 CLAUDE.md 集成:安装 post-commit 自动重建钩子、把 graphify 接入项目 CLAUDE.md 的说明在 hooks.md。
Honesty Rules:五条不可妥协的输出纪律
剧本末尾的 Honesty Rules 是整份技能的行为底线,也是 graphify 差异化定位的浓缩:
- Never invent an edge. 不确定就用 AMBIGUOUS——边必须可审计;
- Never skip the corpus check warning. 超大语料警告不可省略;
- Always show token cost in the report. 语义抽取成本必须显式呈现;
- Never hide cohesion scores behind symbols. 内聚度给原始数字,不用符号替代;
- Never run HTML viz on a graph with more than 5,000 nodes without warning. 大图可视化必须先行警告。
源码级索引:文档声明到实现的对应关系
| 剧本声明 | 实现位置 | 测试/佐证 |
|---|---|---|
detect() 语料检测与 manifest |
detect.py、detect.py save_manifest |
test_detect.py |
collect_files / extract AST 抽取 |
extract.py、extract.py | test_extract.py |
| 语义缓存读写(prompt 归属) | cache.py、cache.py | test_cache.py |
build_from_json(root, directed) |
build.py | test_build_merge_shrink_guard.py |
cluster / score_all |
cluster.py、cluster.py | test_cluster.py |
god_nodes / surprising_connections / suggest_questions |
analyze.py 起三函数 | test_analyze.py |
to_json shrink-guard(返回 bool) |
export.py | test_build_merge_shrink_guard.py |
diagnose_extraction / format_diagnostic_report |
diagnostics.py、diagnostics.py | test_multigraph_diagnostics.py |
report.generate |
report.py | test_report.py |
_stamped_manifest_files 选择性盖章 |
cli.py | test_incremental.py |
| VS Code 平台装配(manual-paste、verbose) | platforms.toml、gen.py | manual-paste.md |
一句话总结这份剧本的设计哲学:把"LLM 参与的部分"压缩到不可压缩的最小(仅内容文件的语义抽取),把其余一切(解释器、检测、AST、缓存、建图、守护、审计、成本)都写成确定性步骤与可重放文件——而 VS Code 变体与通用版的唯一实质差异,就是 B2 从"Agent 工具派发"退化为"手动派发 + 粘贴",其余九步完全一致。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00