
graphify 外部内容接入实战/graphify add url语料抓取与--watch目录增量建图完全指南【免费下载链接】graphifyTurn any codebase, with its docs, SQL schemas, configs, and PDFs, into a queryable knowledge graph. A /graphify skill for Claude Code, Cursor, Codex, and Gemini CLI: local deterministic AST parsing, every edge explained, no vector store.项目地址: https://gitcode.com/GitHub_Trending/graph/graphifygraphify 默认构建链路把「某个本地目录」解析成可查询的知识图谱但真实开发中语料来源往往是动态的你随时可能丢进来一篇 arXiv 论文、一段推文、一个网页或一段演讲视频也会在 Agent 并行写代码的过程中持续新增与修改文件。本篇技术指南聚焦 graphify 在默认构建之外的两个增量扩展入口——/graphify add url抓取一个 URL 进入语料库并合并进图谱与--watch后台监听文件夹、随文件变化自动重建图谱完整讲解它们的命令用法、URL 类型自动识别、目录监听的分流策略并结合 ingest.py、watch.py、transcribe.py、security.py 的源码实现说明底层是如何保证安全、防重、去抖与原子更新的。读完你既能手工把这些命令接进自己的工作流也能理解一个持续保鲜的图谱背后的工程机制。本文依据仓库内已发布到各平台的参考文档整理源文件为片段库中的 tools/skillgen/fragments/references/shared/add-watch.md其在各技能目录下均有同名副本如 graphify/skills/agents/references/add-watch.md。各平台的完整技能文件graphify/skill.md 等在文档末尾统一跳转到该参考当用户运行/graphify add url或传入--watch时加载——这两者都不是默认构建default build的一部分是显式选用的扩展流程。一句话背景为什么需要 add 与 watch默认的/graphify path是一次性的给定目录 → 检测文件 → AST 语义抽取 → 聚类 → 产出graphify-out/graph.json与GRAPH_REPORT.md。add解决语料之外的内容进来把网页/论文/推文/PDF/图片/视频抓进./raw再增量合并进已有图谱。watch解决语料之内持续变化后台盯着目录代码一变就免 LLM 重建文档一变就提示你去跑一次带 LLM 的/graphify --update。两条路径共享一个前置约定——通过graphify-out/.graphify_python记住装了 graphify 的那个 Python 解释器所有后续命令都用它执行从而保证跨会话、跨平台命令可用。前置约定$(cat graphify-out/.graphify_python)是什么文中的命令都形如$(cat graphify-out/.graphify_python) -c ...或$(cat graphify-out/.graphify_python) -m graphify.watch ...。这个写法不是魔法而是 graphify 技能在初始化阶段做的一次解释器固化在首次运行/graphify时技能会把当前可用的 Python 可执行文件路径写入graphify-out/.graphify_python见各 skill 文件的 Step 1例如 graphify/skill.md 中$PYTHON -c import sys; open(graphify-out/.graphify_python,w,encodingutf-8).write(sys.executable)。随后任何一步都可以cat出该路径直接执行保证使用的是确实安装了 graphify 依赖的那个解释器而不是可能与pip环境不一致的裸python3。该机制同样被钩子系统复用在 graphify/hooks.py 中解释器探测的优先级之一是读取graphify-out/.graphify_python。两点实用说明输出目录名graphify-out并非写死常量其单一事实来源在 graphify/paths.pyGRAPHIFY_OUT os.environ.get(GRAPHIFY_OUT, graphify-out)可通过GRAPHIFY_OUT环境变量覆盖如 worktree / 共享输出场景全仓库统一遵守。如果graphify-out/被删过导致.graphify_python丢失技能中有解释器守卫逻辑会先重新解析并回填该文件再继续执行子命令。一、/graphify add url把任意 URL 变成图谱语料1.1 核心调用骨架/graphify add的动作是抓取一个 URL 加入语料库然后更新图谱。参考文档给出的标准执行片段如下$(cat graphify-out/.graphify_python) -c import sys from graphify.ingest import ingest from pathlib import Path try: out ingest(URL, Path(./raw), authorAUTHOR, contributorCONTRIBUTOR) print(fSaved to {out}) except ValueError as e: print(ferror: {e}, filesys.stderr) sys.exit(1) except RuntimeError as e: print(ferror: {e}, filesys.stderr) sys.exit(1) 占位符替换规则占位符含义备注URL实际抓取地址必填AUTHOR内容原作者用户提供时填写CONTRIBUTOR将该内容加入语料库的人用户提供时填写通常用于团队图谱标注归属错误处理契约也是 Agent 行为规范如果命令以错误退出必须向用户说明出错原因不能静默继续只有保存成功后才自动对./raw执行--update增量管线把新文件合并进既有图谱。该调用对应的 CLI 入口在 graphify/cli.py 中同样存在且支持--dir指定目标目录Usage: graphify add url [--author Name] [--contributor Name] [--dir ./raw]从 ingest.py 的ingest()实现可见完整流程target_dir.mkdir(parentsTrue, exist_okTrue)确保./raw存在_detect_url_type(url)判定 URL 类型validate_url(url)做安全校验不合法时抛ValueError按类型分派抓取PDF/图片/YouTube/推文/arXiv/网页网络错误HTTPError/URLError/OSError统一包装为RuntimeError文件名冲突时自动追加_1、_2计数器上限 1000 次避免覆盖已有文件。1.2 支持的 URL 类型自动识别与产出物参考文档定义了 6 类自动识别的来源产出物与后续处理各不相同YouTube / 任何视频 URL→ 经 yt-dlp 下载音频下次运行时转录为.txt需要pip install graphifyy[video]该 extra 写法与 transcribe.py 中的提示一致Twitter/X→ 经 oEmbed 获取存为带推文正文与作者的.mdarXiv→ 摘要 元数据存为.mdPDF→ 直接下载为.pdf图片.png/.jpg/.webp→ 直接下载下次运行时由 Claude vision 抽取任意网页→ 经 html2text实现中为markdownify带降级方案转换为 markdown。URL 类型判定的先后顺序可从 ingest.py 的_detect_url_type源码中精确还原含文档未细列的 github 分支含twitter.com或x.com→tweet含arxiv.org→arxiv含github.com→github直接以普通网页方式抓取含youtube.com或youtu.be→youtube路径以.pdf结尾 →pdf路径以.png/.jpg/.jpeg/.webp/.gif结尾 →image其余一律 →webpage各类型的落地细节对应源码佐证推文_fetch_tweet先把x.com规整为twitter.com请求publish.twitter.com/oembedomit_scripttrue再从返回 HTML 中剥离标签得到纯文本正文与author_nameoEmbed 失败时降级保存 could not fetch content 的 URL 占位文件绝不静默丢弃。产出为带 YAML frontmattersource_url/type: tweet/author/captured_at/contributor的.md。arXiv_fetch_arxiv用正则(\d{4}\.\d{4,5})从 URL 提取论文 ID改走export.arxiv.org/abs/id抓摘要、标题、作者文件名规范为arxiv_id 中点转下划线.md如arxiv_2401_12345.md。PDF / 图片_download_binary字节流直写不经过任何文本转换。视频ingest.py 委托 transcribe.py 的download_audio先经validate_url安全校验再用 yt-dlp 下载bestaudio下载文件名用 URL 的 SHA-1 前 12 位做稳定名yt_hash.m4a/.opus/...并做已下载缓存检查避免重复下载。真正的语音转写由 faster-whisper 在后续--update中完成。网页_fetch_webpage优先markdownifyATX 标题、-无序列表、剥除img缺失时降级为正则剥标签并截断抽取title写入 frontmatter正文默认截断到 12000 字符。1.3 抓下来的文件长什么样无论哪种类型最终写入语料库的文本文件推文/arXiv/网页都带统一格式的 YAML frontmatter供后续抽取器当作节点元数据读取。以网页为例ingest.py--- source_url: https://example.com/post type: webpage title: A great technical post captured_at: 2026-09-07T03:53:4700:00 contributor: someone --- # A great technical post Source: https://example.com/post --- 转换后的 markdown 正文需要特别指出的是 YAML 转义的安全性设计抓取到的页面标题、作者名等外部不可信字符串要嵌入双引号标量若不做转义可能被用于注入同级 YAML 键源码注释中记作 F-009 / F-019。因此 ingest.py 的_yaml_str()手工实现了完整的 YAML 双引号转义——覆盖\\、\、\n、\r、\t、\0连 Unicode 行分隔符 U2028\L与段分隔符 U2029\P都不放过其余控制字符走\xNN转义且刻意不依赖 PyYAML。1.4 安全边界这不是一次裸网络请求URL 抓取天然是 SSRF 重灾区graphify 在 security.py 中做了完整防护ingest 全程经由这些原语validate_url只放行http/https拦截file://、ftp://、data:等 scheme并解析域名解析出的 IP禁止私网段127.x、10.x、169.254.x 等与云元数据端点从源头防 SSRFsafe_fetch重定向会经_NoFileRedirectHandler二次校验响应体按max_bytes流式限量读取超时默认 30ssafe_fetch_text文本抓取的轻量封装默认 15s 超时UTF-8 容错解码。文件名同样做了落地安全_safe_filename只保留netloc path中的\w-字符压缩连续下划线并截断到 80 字符杜绝 URL 里夹带的路径穿越或超长文件名问题。二、--watch让图谱随文件变化自动保鲜2.1 启动方式参考文档给出的监听命令$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3INPUT_PATH替换为要监听的文件夹。模块入口在 graphify/watch.pypython -m graphify.watch [path] [--debounce SECONDS]路径缺省为当前目录.--debounce缺省为3.0秒typefloat。启动后会在前台持续运行打印类似[graphify watch] Watching path - press CtrlC to stop的信息按 CtrlC 停止。--debounce默认 3s的含义等文件活动完全停止后再触发。这样一拨并行 Agent 写出的几十个文件不会每个都触发一次重建——事件会被聚合到安静 3 秒后的单次批处理里。此语义在 watch.py 的watch()主循环中实现事件处理器只记录last_trigger时间戳与待处理集合主线程每 0.5s 醒来检查一次time.monotonic() - last_trigger debounce达标才把整批文件送入处理。2.2 两条处理分支按文件类型分流参考文档规定了监听的核心分流策略仅代码文件变化.py、.ts、.go 等立即重新执行 AST 抽取 重建 聚类不需要 LLM。graph.json与GRAPH_REPORT.md自动更新。文档 / 论文 / 图片变化写入graphify-out/needs_update标记并打印提示让你运行/graphify --update需要 LLM 语义重抽取。从源码看分流逻辑落在两处判定上watch.py_batch_triggers_rebuild(batch)批量内有代码文件或存在被删除的文件→ 触发即时重建。删除任何受监听文件也会重建因为驱逐失效节点同样不需要 LLM代码注释记录为 #2580否则仅删文档的批次会一直挂在needs_update标记后面直到下一次代码事件或手动 update 才生效。_batch_needs_llm_flag(batch)批量内存在仍存活的非代码文件 → 写needs_update标记。已删除的非代码文件不写标记它已被上面的删除重建路径清理干净纯删除批次不会留下过期标记。写标记的实现是_notify_only在graphify-out/needs_update写入1并打印三条提示——检测到新文件、非代码文件需要 LLM 语义抽取、请运行/graphify --update。2.3 事件监听的工程细节底层的watch()watch.py使用 watchdog 观察目录细节决定了它在真实机器上不会误触发、不自循环观察者选择macOS 上使用PollingObserverFSEvents 会漏掉部分编辑器的快速保存其余平台用原生Observer均以recursiveTrue递归监听子目录。事件过滤目录事件与只读事件opened、closed_no_write直接丢弃——否则 watcher 自己重建时读文件会把自身触发的打开事件当成修改无限自循环烧 CPU_is_read_only_event。忽略规则启动时一次性加载.graphifyignore并按需合并.gitignore语义先于扩展名检查短路点号开头的路径组件与graphify-out自身目录被排除只关心_WATCHED_EXTENSIONS代码 文档 论文 图片扩展名的并集见 watch.py。2.4 代码重建的完整调用链与防错设计代码批次触发的_rebuild_codewatch.py 起远比重跑一次 extract复杂它在增量正确性上做了大量防护值得展开re-detect 并沿用持久化排除项重建会再次调用detect()但必须重新套用首次 extract 时记录的--exclude与 gitignore 决策持久化在graphify-out/.graphify_build.json否则每次重建都会把当初故意排除的路径悄悄捡回来#1886。增量 re-extract只对新抽取的 AST 文件重跑extract()_reconcile_existing_graph把既有 graph.json 中未变化文件的节点/边/超边保留下来并把磁盘上已删除来源对应的旧节点驱逐eviction实现增删改都在一次 update 里正确落地。语义层共存保护已有 LLM 语义节点semantic-backed的文档不会被 AST 快速扫描重复铸点#1915/#1954避免文档在图上被表示两遍。拓扑比较快速路径先把候选图与旧图做规范化比较若拓扑与报告都未变化直接跳过聚类与文件重写打印No code-graph changes detected以省去不必要的 I/Owatch.py 等处的same_graph/same_topology判定。原子写与临时文件graph.json先写graphify-out/.graph.tmp.json再replace原子替换崩溃不会留下半截 JSON。防意外缩水守卫_check_shrink若新图节点数明显少于旧图且无法用本次重建的文件集/显式删除解释会拒绝覆盖并提示你检查 chunk 文件缺失必要时用--force强制例如大重构后节点数合法变少。并发互斥per-repo 的 flock 重建锁graphify-out/.rebuild.lock锁文件内写当前持有者 PID拿不到锁的增量提交先把变更集追加进graphify-out/.pending_changes队列持锁方重建前后两轮 drain 并合并#1059确保一波并发提交不会丢任何一次变更。重建成功时输出类似[graphify watch] Rebuilt: 1420 nodes, 3891 edges, 7 communities [graphify watch] graph.json, graph.html and GRAPH_REPORT.md updated in graphify-out若之前生成过 callflow HTML*-callflow.html重建后也会按需重新生成缺失或过期的graph.html则由_reconcile_graph_html从 graph.json 中已有的社区与标签独立重建。2.5 有 LLM 时的配合入口check-update对于只写标记、不即时处理的非代码变更仓库还提供 cron 友好的配套命令graphify check-update pathwatch.py只检查graphify-out/needs_update是否存在并打印提示任何情况下都返回成功True因此放进定时任务不会产生告警噪音。三、Agentic 工作流中的组合用法参考文档对--watch的定位很明确为 Agent 多轮迭代服务。推荐的编排方式是在后台终端运行--watch让代码变更在每一波 Agent 写入之间被自动拾取——AST 抽取免 LLM批量代码改动会在静默 3 秒后自动完成重建与聚类如果 Agent 同时还在写文档或笔记.md、论文、图片watch 只会写needs_update标记并提示你需要在这些波次结束后手动执行一次/graphify --update用 LLM 语义重抽取把新增内容真正并入图谱/graphify add url则是把语料库外的内容论文/推文/网页/PDF/视频/图片先落到./raw再走同一条--update增量管线合入。两者配合的本质是零成本保鲜的权衡代码图可以全自动确定性 AST无 LLM语义层需要人工/LLM 的一下确认文档语义抽取成本高watch 用一个标记文件把这个待办显式化避免遗忘。四、测试与源码佐证该模块的正确性有完整测试背书可直接阅读 tests/test_watch.py 加深理解其中覆盖了文档描述的关键语义test_watched_extensions_includes_code确认监听扩展集合包含代码文件test_batch_doc_only_deletion_triggers_rebuild/test_batch_doc_only_deletion_skips_llm_flag纯文档删除会触发重建、但不写 LLM 标记对应第 2.2 节的分流test_batch_modified_doc_only_does_not_rebuild/test_batch_code_file_still_triggers_rebuild修改文档不即时重建、修改代码即时重建test_rebuild_code_evicts_nodes_from_deleted_files删除文件后其节点被驱逐test_rebuild_code_is_idempotent_when_cluster_ids_flap、test_rebuild_code_skips_cluster_when_topology_unchanged无变化时输出不被反复改写test_rebuild_lock_*系列并发重建锁行为test_rebuild_honors_persisted_excludes重建时沿用持久化的排除项。另外若你的项目把语料放在非./raw目录可用 ingest.py 的独立 CLIpython -m graphify.ingest支持--author/--contributor直接抓取效果与/graphify add等价。小结/graphify add url与--watch是 graphify 知识图谱从一次性快照进化为持续更新的活图的关键通道前者靠 URL 类型识别 安全抓取 YAML 消毒 自动合并把外部内容以统一 frontmatter 形态沉淀进语料库后者靠 watchdog 事件分流、3 秒去抖、AST 免 LLM 即时重建与needs_update标记让代码与语义内容在零成本自动与LLM 介入确认之间取得正确平衡。理解这两条路径的源码级行为防缩水守卫、并发锁、原子写、增量 reconcile你就既能安全地把它接入 CI 或 Agent 工作流也能在遇到图没更新/被拒写/丢变更时快速定位到对应的保护机制。【免费下载链接】graphifyTurn any codebase, with its docs, SQL schemas, configs, and PDFs, into a queryable knowledge graph. A /graphify skill for Claude Code, Cursor, Codex, and Gemini CLI: local deterministic AST parsing, every edge explained, no vector store.项目地址: https://gitcode.com/GitHub_Trending/graph/graphify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考