
graphify 的 add 与 --watch 深度解析URL 内容摄入知识图谱与文件夹监听自动更新【免费下载链接】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 除了对本地代码、文档、SQL、配置做确定性 AST 解析外还提供两条把外部世界纳入知识图谱的通道/graphify add url将任意 URL视频、推文、arXiv 论文、PDF、图片、网页抓取落盘到./raw语料库以及--watch文件夹监听器在文件变动时自动重建图谱。本文以 graphify 的 skill 参考文档add-watch.md为骨架结合 graphify/ingest.py 与 graphify/watch.py 的源码实现完整讲解这两条通道的命令用法、URL 类型自动分派机制、防抖与双路更新策略以及needs_update标志如何与/graphify --update形成闭环。这两个入口在 skill 体系中的定位参考文档开头就明确了加载条件只有当用户执行了/graphify add url或传入了--watch时Agent 才需要加载这份参考文档二者都不属于默认构建流程原文Neither is part of the default build。也就是说一次普通的 graphify 构建只扫描本地目录add与--watch是两个可选项分别解决语料从哪来与图谱如何保鲜的问题。两个命令都通过同一行模板调用$(cat graphify-out/.graphify_python) -c ...其中graphify-out/.graphify_python是 graphify 构建时写入的解释器标记文件保证 Agent 使用的是安装 graphify 的那个 Python 环境graphify/hooks.py 中的 hook 逻辑也读取同一标记来定位解释器。这一点在下面的两段命令中同样适用。/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团队图谱场景下的贡献者名同样可选。文档同时规定了两条行为约束出错必须显式上报——命令以错误退出时要告诉用户哪里出了问题而不是静默继续对应上面捕获ValueError/RuntimeError并写 stderr、退出码 1 的处理成功后自动续跑--update——文件保存成功后立即在./raw上运行--update流水线把新文件合并进已有图谱而不需要用户再手动触发。源码印证ingest() 的分派流程上述命令最终调用的是 graphify/ingest.py 中的ingest(url, target_dir, author, contributor)。其执行顺序在源码中非常清晰确保目标目录存在target_dir.mkdir(parentsTrue, exist_okTrue)调用_detect_url_type(url)分类 URL调用validate_url(url)做安全校验来自 graphify/security.py按类型走不同分支网络异常统一包装为RuntimeErrorURL 非法则抛ValueError——这正与命令模板中捕获的两种异常类型一一对应。URL 类型自动检测参考文档列出的类型表Supported URL types, auto-detected与源码_detect_url_type()graphify/ingest.py完全吻合检测规则是纯字符串/后缀判断URL 类型检测规则落盘形式后续处理YouTube / 任意视频含youtube.com或youtu.be音频文件.m4a/.opus等下次构建时由 Whisper 转写为.txt需要pip install graphifyy[video]Twitter / X含twitter.com或x.com.mdYAML frontmatter 推文正文与作者通过 oEmbed 抓取arXiv含arxiv.org.md摘要 元数据通过 export API 抓取摘要PDF路径以.pdf结尾.pdf原文件直接下载二进制图片.png/.jpg/.webp 等路径以图片后缀结尾原格式图片文件下次构建时由 Claude vision 抽取任意网页以上均不命中.mdfrontmatter 正文 markdown默认兜底分支几个值得注意的实现细节均来自 graphify/ingest.py 源码视频分支url_type youtube时延迟导入from graphify.transcribe import download_audiographify/transcribe.py用 yt-dlp 下载最佳音频流文件名基于 URL 的 SHA-1 前 12 位生成yt_hash.ext已存在同名文件时直接命中缓存、跳过下载。对应的安装依赖即 pyproject.toml 中的可选依赖组video [faster-whisper; python_version 3.11, yt-dlp2026.6.9]。推文分支先把x.com归一化为twitter.com再请求publish.twitter.com/oembed接口取html与author_nameoEmbed 失败时不报错而是写入一条 could not fetch content 的占位说明保证 URL 至少以存根形式进入语料库_fetch_tweetgraphify/ingest.py。arXiv 分支用正则(\d{4}\.\d{4,5})从 URL 提取论文 ID改向export.arxiv.org/abs/id抓取标题、作者与摘要提取不到 ID 时降级为普通网页处理。文件名固定为arxiv_ID.md点号换下划线与 URL 形态无关便于去重识别_fetch_arxivgraphify/ingest.py。网页分支先提取title再做 HTML → Markdown 转换。参考文档写的是via html2text而从源码看_html_to_markdown()实际优先使用 markdownify若已安装否则回退到去标签 空白折叠的兜底实现截断 8000 字符正文最终以markdown[:12000]写入文件控制单个抓取页面的规模上限graphify/ingest.py。所有文本类落盘文件都带 YAML frontmatter记录source_url、type、author/title/arxiv_id、captured_atUTC ISO 时间与contributor——这些字段会在后续提取时成为图谱节点的元数据--author/--contributor参数就是在这里生效的。安全与命名细节ingest()路径上有几道在参考文档中未展开、但值得了解的保护措施URL 校验所有抓取前都经过validate_url()在请求发出前拦截私有 IP 与非法 schemeSSRF 防护graphify/transcribe.py 中同样在下载前调用并附有注释说明。文件名净化_safe_filename()把netloc path中所有非[\w-]字符替换为_、折叠连续下划线、截断到 80 字符避免抓取路径写入非法文件名graphify/ingest.py。防覆盖目标文件已存在时自动追加_1、_2… 计数后缀上限 1000不会静默覆盖语料库中的旧文件graphify/ingest.py。YAML 注入防护抓取来的标题/作者等外部字符串一律经过_yaml_str()转义后再嵌入 frontmatter覆盖\n、\r、\t、\0以及 U2028/U2029 等所有 YAML 行分隔符防止恶意页面标题逃逸出双引量标注入兄弟键graphify/ingest.py。--watch文件夹监听与自动更新命令模板参考文档给出的第二条命令$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3把INPUT_PATH替换为要监听的文件夹即可。--debounce的单位是秒默认值 3 秒。双路更新策略按变了什么决定怎么做这是 watch 的核心设计文档将其表述为两种行为源码在 graphify/watch.py 的watch()函数中有逐行对应只有代码文件变更.py、.ts、.go 等立即重跑AST 提取 重建 聚类全程不需要 LLMgraph.json与GRAPH_REPORT.md自动更新。源码中这一步由_rebuild_code(watch_path)执行内部串联detect → extract → build → cluster → analyze → report → to_jsongraphify/watch.py 中的导入清单即为该调用链。文档、论文或图片变更写一个graphify-out/needs_update标志文件并打印提示告知需要运行/graphify --update才能完成 LLM 语义重抽取。这一步由_notify_only()实现graphify/watch.py它只写标志、不尝试重建——因为语义层节点无法用纯 AST 路径再生。两条路径的判定函数分别值得看一下graphify/watch.py_batch_triggers_rebuild(batch)批内任一文件后缀属于代码扩展名或任一文件已被删除时立即重建。注意任意文件删除也触发重建这一细节删除后的陈旧节点淘汰eviction同样不需要 LLM若只按是否有代码变更判断一个纯文档删除批就会被搁置在needs_update标志后面。_batch_needs_llm_flag(batch)只有仍然存在于磁盘上的非代码文件才需要写needs_update标志已删除的非代码文件交给重建时的对账清扫处理纯删除批不会留下陈旧标志。另外源码还有一层文档未提的兜底_rebuild_code用 per-repo 的flock咨询锁graphify-out/.rebuild.lock加.pending_changes排队文件保护重建过程避免多进程并发重建互相覆盖graphify/watch.py。防抖Debounce机制参考文档对防抖的解释是等到文件活动停歇后才触发避免并行 Agent 写入的浪潮按文件逐个触发重建。源码实现graphify/watch.py与此描述一一对应主循环每 0.5 秒醒一次事件到来时只记录last_trigger time.monotonic()并把路径累加进changed集合不立即重建只有当pending为真且距离最后一次触发已不小于debounce秒时才把整批路径取出、清空集合然后打印N file(s) changed并执行上述双路判定。因此--debounce 3的含义是最后一次文件变动后静默 3 秒一波连续写入只会产生一次重建。CLI 参数解析见 graphify/watch.py位置参数path缺省为.--debounce为浮点数、默认 3.0。事件过滤watch 到底看什么watch()基于 watchdog 库在注册 handler 之前有一组过滤规则graphify/watch.py扩展名白名单_WATCHED_EXTENSIONS是代码、文档、论文、图片四类扩展名的并集CODE_EXTENSIONS | DOC_EXTENSIONS | PAPER_EXTENSIONS | IMAGE_EXTENSIONS来自 graphify/detect.py白名单之外的事件直接丢弃.graphifyignore优先短路模式在启动时只解析一次每个事件先查忽略规则再查扩展名避免高负载卷上的无效事件耗尽 CPU点目录与输出目录路径中任何一段以.开头、或位于graphify-out/内的变更一律忽略——后者尤其重要否则重建产物本身又会被当成输入形成自我触发只读事件过滤Linux 上 inotifywatchdog ≥ 2.3 / ≥ 4会对每次打开/关闭文件产生opened、closed_no_write事件包括 watcher 自己读文件、hook stat 源码在内源码将这两类显式视为读而非变更只把创建、修改、移动、删除与 close-after-write 当作变更_is_read_only_eventgraphify/watch.pymacOS 特殊处理sys.platform darwin时改用PollingObserver因为 FSEvents 在某些编辑器下会漏掉快速保存graphify/watch.py。watch 启动时的标准输出也值得留意它会直接告诉用户两条通道各自的语义[graphify watch] Watching abs-path - press CtrlC to stop [graphify watch] Code changes rebuild graph automatically. Doc/image changes require /graphify --update. [graphify watch] Debounce: 3.0s按文档说明CtrlC即可停止handler 捕获KeyboardException后打印Stopped.并停止 observer。面向 Agent 工作流的用法参考文档最后一段给出了在 Agent 化流程中的部署建议把--watch放在后台终端运行。这样 Agent 分波wave写代码时波与波之间的代码改动会被监听器自动拾取并重建图谱但如果同一批 Agent 还写了文档或笔记那些变更只会留下needs_update标志需要在相应波结束后手动补一次/graphify --update。这与上一节的双路策略是同一逻辑的使用侧表述。needs_update 标志的闭环check-update 与读取提示needs_update标志不是只写不读的产物graphify 为它提供了消费端graphify check-update path子命令检查标志是否存在存在则打印有待处理的非代码变更请运行/graphify --update它总是返回成功cron-safe适合放进定时任务轮询命令帮助见 graphify/main.py实现check_update只读标志、不清除——清标志是执行--update的职责。读取钩子Agent 通过 Read 工具读取项目文件时graphify/cli.py 中的 hook 逻辑会把graphify-out/needs_update的存在视为图谱已陈旧的信号向 Agent 提示图谱落后于磁盘状态从而引导其在问答前先触发更新。这两个消费端保证了文档变更后忘记跑--update这件事最终会被系统自己发现而不是静默地用旧图谱回答问题。测试覆盖上述行为均有对应测试可供查证tests/test_ingest.pyURL 分类、抓取落盘与异常路径tests/test_watch.pyneeds_update标志的写入/读取、check_update不删标志、代码/文档混合批次的分发判定以及用debounce0.2在真实文件系统事件下驱动watch()的端到端用例tests/test_transcribe.py视频音频下载与转写tests/test_security.pyvalidate_url等抓取前安全校验。适用前提与限制结合 pyproject.toml 与源码使用本文两条通道时的适用前提如下add的可选能力依赖 extras视频转写需要pip install graphifyy[video]提供 yt-dlp 与 faster-whisper且 faster-whisper 要求 Python ≥ 3.11网页→Markdown 的质量取决于是否安装了 markdownify否则回退到基础去标签实现并截断正文。抓取目标必须通过安全校验私有地址、非法 scheme 会在发出请求前被拒绝add因此无法用于摄入内网资源 URL。--watch依赖 watchdog缺失时watch()会明确报出安装提示而非静默失败macOS 上自动切换为轮询观察器行为与 inotify 略有差异。watch 只负责代码层保鲜与语义层提示文档/论文/图片的语义节点永远需要/graphify --update的 LLM 流水线补齐这是设计上的边界不是缺陷。综上graphify 的add与--watch一条解决语料入口任意 URL 类型自动分派、安全抓取、防覆盖落盘一条解决图谱时效防抖批处理、代码变更免 LLM 即时重建、非代码变更以标志文件提示语义更新二者共同让任何代码库 其文档构成的知识图谱可以随时间与外部信息持续生长。【免费下载链接】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),仅供参考