关于 geo-sleuth
geo-sleuth 是用于照片地理定位的技能,帮助调查者寻找可追溯证据支持的位置。脚本化候选板记录线索、排序、排除和验证,让结论可依据命令及生成文件复核。
主要功能
- 01关联证据的候选项追踪
- 02线索记录与评分
- 03地理候选位置排序
- 04脚本化排除检查
- 05图像与地形分析流程
适用场景
- 01定位照片并记录支持线索
- 02根据地理证据比较候选区域
- 03无法验证具体点位时报告范围
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ oldcircle/ geo-sleuth --skill geo-sleuth安装后在 Claude Code 中输入/geo-sleuth确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
data/calling_codes.jsoncountry_names.jsondriving_side.jsonREADME.mdterritories.jsonreferences/aerial.mdcorridors.mddata-sources.mdgeometry.mdobserve.mdsearch.mdsky.mdskyline-fallback.mdverify.mdreferences/clues/global.mdREADME.mdregions/_template/clues.mdREADME.mdregion.jsonregions/ca/clues.mdregion.jsonregions/cn/clues.mdregion.jsonsearch.mdtests.jsonregions/cn/data/admin.jsonarea_codes.jsonplates.jsonregions/il/clues.mdregions/il/data/admin.json详细介绍
geo-sleuth (v2)
目标:找到一个经得起核查的地点。每个结论都必须指出所依据的线索、运行的命令以及生成的文件。
命令中的
${CLAUDE_SKILL_DIR}表示包含此 SKILL.md 的目录(references 中命令的含义相同)。Claude Code 会自动替换它;在其他 Agent 中,运行前先执行export CLAUDE_SKILL_DIR=<此目录的绝对路径>(如果 shell 不会在命令之间保留变量,则在每条命令前加上它),或者直接将它替换为该路径。
工作分为三个层次。请先记住这一点,再阅读流程:
| 层次 | 负责方 | 工具 |
|---|---|---|
| 决策:有哪些候选地点、如何对证据评分、是否可以排除某个候选地点、接下来扫描什么 | 脚本(候选地点看板) | board.py |
| 感知:读取文本、查表、在卫星图像中查找目标、匹配街景 | 脚本先计算并排序;你只看排名靠前的少数结果 | intake.py ocr.py clues.py sat_scan.py match.py geo.py bearings |
| 判断:从图像中提取线索、在表格中找不到信息时提出假设、在机器筛出的少数结果中做出判断 | 你 | — |
本方法源于对 14 个照片地理定位(网络迷踪)创作者视频和 22 个谜题的拆解,以及多轮盲测对比;拆解笔记未随仓库发布。v1 的经验是:以散文形式编写的规则不会被执行,而且同一技能版本的两次运行会产生截然不同的结果;因此,v2 将所有可以写成代码的规则都放进了 board.py。
硬性规则(始终生效;★ = 由 board.py 强制执行,只需遵循即可)
- 如果用户说照片不是他们的,或者图中有私人住宅或未成年人,请先询问一次照片的用途,再继续;如果提示中已说明来源或用途(评估谜题、谜题作者的提示、用户说是他们拍的),则不要询问,照常查到最精细的级别。
- 不要捏造验证结果。“在地图上测量过”“与街景匹配”“±10 m”必须对应本次会话中实际运行的命令和实际生成的文件。如果没有运行,就写“未经验证”。
- 精度需要依据:误差半径 ≤100 m 时,必须满足两项独立约束的交集,或与地面实景中的 ≥3 个不变特征匹配。在报告相机位置前,先进行自检:
pose.py project --horizon <sea-horizon row>会计算当前相机位置应有的俯仰角,以及每个特征的“预期行”;将这些结果与照片核对(目标的俯角 ≠ 相机的俯仰角;使用terrain.py elev查询相机位置的海拔——如果高度差与图中的俯角不符,则相机位置有误)。 - 找到唯一锚点后,闭环验证:之后所有搜索和几何推算都从该锚点开始;不要退回到“蓝绿色湖水”或“热带公园”之类的泛泛特征,再挑选这类地点中最著名的一个。
- 先计算方位,再识别结构:卫星影像中哪个街区对应照片里的塔楼或烟囱,本身就是一种解读。先用
sun.py compass或已确认的地标计算其在图像中的真方位角,再用geo.py bearings查看候选相机位置周围哪个轮廓落在该方位上;如果没有符合的,先尝试两种模板(“原图/镜像”“日出/日落”);如果仍未验证,只降低级别,不要排除。 - ★ 推断前先列出整个类别:根据“山城”“热带”“某市辖区内的 IP”推断地区时,使用
board.py children将所有下级行政区划添加为候选项,再依据证据排序。不要默认选择主要城区,也不要按人口挑选。 - 元数据和提示只是假设:当 EXIF、IP 位置、位置标签或谜题作者的文字与图像冲突时,以图像为准;不要编造说法来调和矛盾。IP 指向国家 A,但提示或法规设计(车牌、标志)指向另一个大洲时:使用
clues.py lookup territories <country A> --continent <continent>。 - 自洽性:使用不同的裁剪图或关键词集,将每项关键判断重新做一次;如果两次结果相差数十公里或更多,就降低级别。
- ★ 如果无法确定一个点,就给出范围 + 缺少的信息;如果候选项是几个离散地点,不要取中点:
board.py report的主要答案始终是排名最高的候选项;其余候选项放入备选项,并附上能区分它们的测试。 - ★ 排除和确认使用相同标准:
board.py exclude只接受已读取/计算的线索 + 计算生成的文件(geo.py frame、terrain.py等的输出);观察和推断所得的线索只能通过evidence --against降低权重,似然比限制在 1/3–3(推断所得)或 1/5–5(观察所得)。根据“附近有 X”生成候选项也属于筛选,而 X 必须是图像中已确认的事物。校园、住宅区和街道路段等精细级别的候选项也必须放入候选板:使用board.py add --from <poi.py --out / osm.py geom output> --level area/road一次批量添加,不要手动挑选;放弃某个候选项时,使用对比图写入evidence --against;check会列出没有任何证据的候选项(表示没人查看过它们);更精细的候选项应归入包含它的候选项之下(例如,将一个点归入其所在街道路段:使用--parent或board.py move),这样它的支持证据才会计入该级别的排名;如果跳过某个级别,check就会失败;第三方数据中的标签(市政清单中的树种、完全匹配的学校名称)只能降低权重,绝不能作为排除依据(有两次案例中,真相正是因此被手动跳过)。排除的范围不得超过证据覆盖范围:对于有范围的候选项,例如区、区域和道路,exclude需要通过--covers lat,lon[:lat,lon]指明证据覆盖的路段;脚本会拒绝覆盖范围不足一半的情况(有两次案例中,仅查看一个点后就排除整条道路,均告失败)。 - ★ 人口和知名度不是证据;扫描顺序遵循“份额 ÷ 页面数”(
board.py next):先完成较小的区,把大区放到最后,并设置页面上限。
流程
无需完成每一步:如果第 1 步的反向图片搜索直接命中,可跳到第 6 步和第 7 步进行确认。每一步的输出都放到候选板上。
第 1 步:用一条命令完成步骤 0–3
uv run ${CLAUDE_SKILL_DIR}/scripts/intake.py photo.jpg --out-dir intake/ [--box x0,y0,x1,y1 ...]
uv run ${CLAUDE_SKILL_DIR}/scripts/board.py init --photo photo.jpg
intake.py 通常需要 1–2 分钟,首次运行时由于要安装依赖,耗时会更长:请为命令设置充足的超时时间(10+ 分钟),或在后台运行。如果命令因超时而中断,反向图片搜索子进程可能仍在写入 rev/,但不会生成 intake.md;不要将其视为已完成。
intake.md 包含:元数据、OCR 文本(从放大/分块处理结果中读取的行会标记为 pass=up/tile,属于假设)、百度相似图片(来源网站计数 + 编号联系表)、带分级票数的反向图片搜索标签、可能的住宅小区/开发项目名称、边缘裁剪图列表,以及失败项目。接下来要做四件事:
- 查看图片:检查
edges/中的每张裁剪图(四条边、四个角);按references/observe.md中的清单逐项检查;使用board.py clue "<text>" --kind <kind> --status observed|read|inferred|computed --file <zoomed crop>记录每条线索。务必如实标注状态:读到的文字标为 read;“建筑大概有 8 层”“道路是上坡”则属于推断。 - 如果某项计算结果确实检验了较早记录的线索,请用
clue "<result>" --kind <kind> --status computed --file <output> --resolves K1将其关联(有多条线索时重复使用--resolves)。无关的计算不能解决待确认的基础设施线索;此关联记录的是检验,而非对某个地点的支持。 - 查询表:全球范围适用电话区号、行车方向和海外领地;车牌、区号及其他国家表格来自区域包 →
clues.py lookup <kind> <value> [--country <cc>](不使用--country时会搜索所有区域包,并返回来自多个国家的匹配结果)。如果查询结果能确定某个行政区划,请直接使用board.py apply --kind plate --value <plate prefix> --file <zoomed crop>(会自动添加候选地点和证据;同一层级的其他候选地点只会降低权重,不会被排除)。 - 反向图片搜索结果:先打开
rev/<name>_baidu_similar.jpg(左上角的图块是查询图片),查找同一物体或同一场景的相似图;如有相似图,请按编号在 JSON 中查看similar[i].from对应的来源页面;标签中的小区、开发项目或酒店名称 → 使用poi.py "<name>" --city <city> --out pois.json获取坐标;对于同名结果(多个校区、多个分店),使用board.py add --from pois.json --level area将它们全部加入候选板,然后逐一核查;务必打开截图,一旦命中某篇帖子,就查看该帖其余的照片。根据物体类型选择搜索位置(references/search.md)。 - 提示和元数据:将每项记录为推断线索,并说明其可信度;IP 位置只能说明发帖者发帖时所在的位置,发帖时间不等于拍摄时间。
- 国家特定资料:在国家范围尚未确定时,查看
references/clues/global.md(用于区分国家的线索)。国家特定线索、表格、首选服务和提示位于区域包(regions/<cc>/)。将某个国家列为候选后,运行regions.py show <cc>:它会打印该区域包中的查询表、服务,以及附有行号的线索条目单行索引;只阅读需要的条目。确定国家后,运行board.py country <cc>,并停止查阅global.md。regions.py list会显示现有区域包;如果没有对应区域包,请使用全局工具。
步骤 2:列出所有候选项、评估证据并检查下一步
uv run ${CLAUDE_SKILL_DIR}/scripts/board.py children <parent admin area> # municipality → all districts; country → first-level admin divisions (gazetteer.py queries OSM, with bbox)
uv run ${CLAUDE_SKILL_DIR}/scripts/board.py evidence --clue K1 --for <candidate A>:5 --for <candidate B>:2 --against <candidate C>:0.3 --why "…" --file <comparison image>
uv run ${CLAUDE_SKILL_DIR}/scripts/board.py rank
uv run ${CLAUDE_SKILL_DIR}/scripts/board.py next
next 只会说以下两种情况之一:
- 无法区分:对所有候选项同时进行区分测试,按成本从低到高依次进行——查询表格 → 地形(平原城市还是丘陵城市,
tiles.py fetch --zoom 13或terrain.py)→ 车辆涂装(用当地语言搜索“<城市> <颜色> 公交车”的图片;从结果图片中读取线路标志,并按城区比较公交车尾部的条纹)→ 街道设施(查看各候选城区的街景)→ 河流/道路网络模板。做完所有测试后仍无法区分:不要停止;按照它给出的“共享数 ÷ 页面数”顺序继续扫描。如果已知地图所在国家,next会用该地区资料包中的提示替换这些内容。 - 可以缩小范围:先用
board.py urban <candidate>将范围缩小到建成区(或用scan-bbox手动指定),然后用board.py falsify <candidate> --text "…"写下一个证伪条件,接着进入步骤 3。
粗略的环境定位规则仍然适用:先看地形,再看河宽和建筑颜色;物候必须结合月份判断;找出罕见设施组合的交集;可识别的物种只能用于排除;如果你掌握的只有土地类型,先用土地覆盖地图将范围缩小到该类型的土地(references/clues/)。
步骤 3:选择一个分支以缩小范围
| 你掌握的信息 | 方法 | 阅读 |
|---|---|---|
| 独特的地标(建筑、雕像、塔楼、景区建筑) | 地标几何:视线交点、对齐线、切线、按相机高度筛选建筑 | geometry.md |
| 远处的山脉、天际线 | 用 terrain.py view 渲染候选相机位置并进行比较;这只能确定一条视线,之后还要寻找第二个约束。没有 EXIF:不要假定使用的是主摄(远处的山脉通常是用变焦拍摄的);如果最佳焦距落在搜索范围边缘,就扩大范围并重新运行。远近景叠加:同时为两个层评分 | geometry.md |
| 清晰的阴影、受光的立面、太阳入镜 | sun.py locate / when / facing / compass:纬度范围、时间、朝向、图中物体的真方位角 | sky.md |
| 路线编号、铁路或电力线路规格、大型河流 | 线性廊道 + 线转点:osm.py route / crossings / along | corridors.md |
| 同一画面中有两三种基础设施 | osm.py near --report;两种线性类型的交叉点用 osm.py intersect(弯道只会标注,不会移除) | corridors.md |
| 线性基础设施 + 无法识别的山脉,没有文字 | 根据基础设施沿线的高程计算地平线并筛选整个区域 → 对天际线评分,并数值化计算与基础设施的距离 → 叠加排名前 3–5 的结果 → 根据间距均匀的结构确定相机位置:terrain.py scan --lines … --out hits.json --clusters-out clusters.json → terrain.py ridge photo.jpg --x0 … --x1 … --out ridge.json → terrain.py fit --hits hits.json --ridge ridge.json [--line … --line-dist …] --sheet top.jpg --photo photo.jpg(精细搜索时切换到 --at lat,lon --radius 800 --grid 100 --zoom 13)→ imgprep.py piers photo.jpg --rows … --out cols.json --sheet piers.jpg → geo.py spacing --cols … --line … --span … --center lat,lon --ridge ridge.json | corridors.md 4.3、geometry.md 7.4 / 7.7 |
| 街道布局清晰,没有地标 | 用 osm.py street-scan 筛选交叉口 → tiles.py sheet → 街景 | corridors.md |
| 反向图像搜索没有相似图,没有文字,只有一组场景元素(道路规格 + 邻近特征 + 地貌) | 不要先手动挑选地点:用一个英文查询描述整个场景,再用 sat_scan.py grid --bbox <coastal strip/corridor> --zoom 17 --cell 360 --query … --neg … 让 CLIP 排序;只查看排名前 20–30 的缩略图;grid 优于 points,因为 OSM 特征(如 amenity=parking)可能不完整 | search.md |
| 画面中有 ≥4 个位置已知的点(窗外景色、俯拍;也包括远处塔楼、桥梁、码头的平视照片——固定高度) | pose.py solve 可求解相机位置、朝向和高度;如果多个候选位置都符合条件,则用 pose.py check --cands 逐一评分;只有稳健的 Δchi2 > 9 才可交给 board.py exclude --computed | geometry.md 第 10 节 |
| 想根据“画面中没有 X”来排除 | 先用 geo.py frame 计算 X 是否应当在画面内、尺寸是否足够大以及是否被遮挡;只有它判定可以用于排除的情况,才能交给 board.py exclude --computed | geometry.md 第 11 节 |
| 可识别类别的无名建筑,且搜索区域已缩小 | 用 osm.py find 枚举 → 用 gsv.py targets 查找每栋建筑附近朝向该建筑的街景 → 用 match.py 排名;分批处理并限制每批范围 | search.md 第 6 节 |
| 可识别的设施类型(谷物烘干塔、饲料厂、糖厂、混凝土搅拌站) | 查询该行业的分布 → 用 osm.py buildings 枚举大型建筑 → 用 sat_scan.py points 排名 | search.md |
| 连锁品牌旗下子品牌的门店 | 先搜索开业新闻稿中的地址;门店查询器仅用于建立候选池 → osm.py along + 街景采样 | search.md |
| 飞机舷窗、无人机俯拍 | 航拍分支 | aerial.md |
第 4 步:在卫星影像中寻找目标——由机器负责排名
uv run ${CLAUDE_SKILL_DIR}/scripts/sat_scan.py grid --bbox <scan_bbox> --zoom 17 --preset track --multi-scale --top 30 --out sat.json --sheet sat_top.jpg --heat heat.jpg
uv run ${CLAUDE_SKILL_DIR}/scripts/poi.py "<district> <school, in the local language>" --city <city> --region <cc> --out schools.json # seeds: --seeds schools.json boosts nearby cells
uv run ${CLAUDE_SKILL_DIR}/scripts/sat_scan.py points --points big.json --preset factory --out r.json --sheet r.jpg # rank candidate points from osm.py buildings / poi.py
- 预设:track(跑道)、stadium(体育场)、factory(工厂)、silo(筒仓)、dam(水坝)、bridge(桥梁)、quarry(采石场)、solar(太阳能设施)、greenhouse(温室)、port(港口);可使用自定义
--query。在测试中,在一个城区的 300 多个网格中,超过一半已被 OSM 标注的跑道都进入了前 30 名;在中国一座 OSM 数据空白的古城中,一所学校的运动场仍排名第一。它负责排名,不负责判断:查看排名前 20–30 个网格的缩略图,再根据照片中的朝向和形状进行核对。 - 在查看影像前,先把图像描述转化为俯视特征:弧形建筑、八角亭顶、运动场地、与铁路垂直的停车位;对于高层建筑,查看其底部;影像有拍摄日期。
- 候选项较多时,制作候选项表:每个点占一行,每个照片中直接可见的判断标准占一列。
- 前 30 名中没有符合项:先回到
board.py check列出的“根据推断而降低权重的候选项”和证伪条件,再切换预设或前往 z18,最后才扩大区域。
第 5 步:确认——街景也由机器负责排名
uv run ${CLAUDE_SKILL_DIR}/scripts/baidu_pano.py scan <lat,lon> --radius 300 --out panos.json # the street-view script the region card names (CN: baidu_pano.py); otherwise gsv.py
uv run ${CLAUDE_SKILL_DIR}/scripts/match.py rank --query photo.jpg --panos panos.json --toward <landmark lat,lon> --spread 15 --refine sift --top 10 --out m.json --sheet m.jpg
uv run ${CLAUDE_SKILL_DIR}/scripts/match.py rank --query photo.jpg --items around.index.json --render gsv --spread-headings -30,0,30 --out m.json --sheet m.jpg
match.py按 DINOv2 全局相似度进行粗略排名,再按 SIFT 内点数进行精细排名;在测试中,同一地点不同年份的真实街景都进入了前 4 名。只打开前 10 名,并比较不变特征(建筑轮廓、窗户位置、阳台、电线杆位置、路缘、山脊线),而不是车辆、标志或植被。道路级确认需 ≥2 个特征,建筑级确认需 ≥3 个特征。没有任何一张图像达到 ≥15 个内点,并不意味着结果有误:季节变化、拍摄时间较早,或照片是在路边拍摄而街景是在路中央拍摄时,测试中的真实地点仅有 5 个和 0–8 个内点(共两种情况);先打开前 10 名并比较不变特征,只有都不符合时,才更改--spread-headings或扩大--within范围。全局分数容易被季节主导(花季拍摄的影像无论地点在哪里都可能排名靠前),因此尽可能找一张与照片同季节的历史影像进行比较(gsv.py sheet --date)。- 全景点较多时,按日期和道路分组;
sheet --road <road name> --spread 60只显示一条道路;较早的影像视野更开阔。 - 没有街景不代表无法确认:使用
terrain.py view --photo比较山脊线;查找候选设施的名称(OSM 名称、附近地点名称 + 当地语言中的设施类型词),并搜索新闻、百科全书和官方网站上的照片,以比较外墙细节。 - 街景比照片早很多年时,根据老建筑和永久性结构进行判断。
第 6 步:确定相机位置并写出结果
- 回头看:在匹配的街景点转身 180°,看看摄影者一侧有什么。
- 相机位置需要两个独立约束(
geo.py intersect视线交点、geo.py line对齐线、pose.py多点求解、相机高度、反向街景);如果只有一个,楼级置信度最高为“中”。 - 没有可测量的阴影时,根据受光面判断朝向:
sun.py facing --lit left --shaded camera。如果照片是在汽车、船或火车上拍摄的,请注明行进方向。
uv run ${CLAUDE_SKILL_DIR}/scripts/board.py check # before concluding: do exclusions have files, does the main answer have verified evidence, which clues went unused
uv run ${CLAUDE_SKILL_DIR}/scripts/board.py report --merge result.json # main answer = top-ranked; alternatives, exclusions and unused clues are written into result.json automatically
uv run ${CLAUDE_SKILL_DIR}/scripts/evidence.py spec.json --out evidence.jpg
将 evidence.jpg 与答案一并展示给用户,不要等用户要求。基于卫星图像得出的道路级结论需要使用 ≥z18 的裁剪图,而不是 z17 的一瞥。
输出:
- 一句话结论:地点 + 相机位置 + 朝向(+ 适用时的行进方向和拍摄时间)
- 坐标:WGS84;如果区域卡片中列出了当地基准,也一并提供(
geo.py convert),并注明误差半径 - 证据图像(标出相机位置和朝向扇区的卫星图像 + 对比图像)
- 推理链:线索 → 推断 → 实际运行的命令和生成的文件 → 范围
- 分级置信度(见下表)。分别评定每个级别;你报告的级别是评为“中”或以上的最精细级别:楼级置信度低不会拉低片区级置信度
- 排除的候选地点及原因、其他可能性及区分这些可能性的测试、未使用或尚未解决的线索(由
board.py report生成) - 无法确定具体点时:说明已确定的级别,以及还需要哪些信息
工具消息、报告标题和生成的标签使用英文。将来源文本(OCR、地名、服务响应)原样保留为证据;向读者解释或翻译这些内容。使用用户的语言撰写 Agent 的最终报告。使用中文时,高/中/低分别对应 high/medium/low,城市/片区/路/楼/楼层分别对应 city/area/road/building/floor。
| 级别 | 高 | 中 | 低 |
|---|---|---|---|
| 城市 | 文本、车牌、区号或已确认的锚点 | 多条独立的弱线索相互吻合 | 单条弱线索,或仅有提示 |
| 片区 | 一个独特的设施或地标与卫星图像中的 ≥3 个俯视特征吻合(已检查整个候选片区,没有第二处匹配) | 候选片区中最相似的位置,但候选地点尚未逐一检查 | 推断所得 |
| 路 | 地面级匹配,至少包含 ≥2 个独特特征 | 布局一致,包含 1 个独特特征;完全没有地面级图像时:片区级置信度为高 + 方位自检通过 | 仅卫星图像布局 |
| 楼 | 两个独立约束 + 地面级匹配,至少包含 ≥3 个特征 | 两个约束之一 | 推断所得 |
| 楼层 | 两种参考信息一致 | 单一参考信息 | 不提供 |
预算与停止条件
intake.py计为一次调用;如果使用 3 组不同的关键词进行反向图片搜索都没有结果,就停止搜索,并返回清单寻找其他线索。- 如果候选项仍无法区分,不要逐个扫描点位(当
board.py next提示“无法区分”时,先进行鉴别测试);如果完成低成本测试后仍无法区分,则按照它给出的顺序扫描,优先扫描每个候选项建成区的前 3 页。 - 扫描和确认始终优先:查看
sat_scan.py的前 30 个单元格和match.py的前 10 张图片;只有排名靠前的结果全部错误时,才扩大范围,而不是逐页翻查。 - 使用 OSM 枚举候选项之前,先运行
osm.py coverage:数据稀疏的地区会被静默排除;请改用sat_scan.py grid,并在结论中说明这一点。 - 每个区域每批最多扫描 500 个全景点。如果一批或多个区域都没有匹配结果,请检查候选项生成方式、搜索覆盖范围和被降低权重的候选项;然后调整方法或扩大有依据的搜索范围。未匹配区域达到某个固定数量,并不构成结束调查的理由。
- 服务故障或不可用只会阻断相应途径,不会阻断整个调查。请考虑其他可行的数据源或方法;不要原样重复失败的请求。
- 停止前,运行
board.py check:按排名顺序重新检查前 20 个因推理而被降低权重、但未排除的候选项。 - 当证据足以支持用户要求的位置层级、用户要求停止、达到用户设定的预算,或没有任何可行的后续操作可能区分候选项时,即可结束。如果仍无法确定位置,请使用
board.py report说明证据支持的位置层级、实际搜索覆盖范围、尝试过的途径、受阻原因和缺失的证据;不要为了结束而编造坐标或精度。
运行环境
- Python 3.10+、
uv和curl。始终使用uv run ${CLAUDE_SKILL_DIR}/scripts/xxx.py;每个脚本都会声明其依赖项。参考资料中的scripts/路径相对于此技能目录。 - 首次设置或运行时发生故障后,运行
uv run ${CLAUDE_SKILL_DIR}/scripts/doctor.py;添加--network以检查服务可达性。开始高成本扫描前,请阅读英文检查结果和修复建议。它不会上传照片,也不会加载 ML 模型。 - 反向图片搜索使用本地 Google Chrome,并在需要时自动回退到 Playwright Chromium(
uvx playwright install chromium)。如果两者都无法启动,请使用intake.py --no-rev,并报告跳过的搜索。OCR 在 macOS 上优先使用 Apple Vision,在其他平台上使用 RapidOCR;也可将其用作后备方案。 match.py和sat_scan.py会安装 ML 依赖项,并在首次使用时下载模型权重。请预留额外时间和磁盘空间。- 缓存位于当前目录下的
.geo-cache/;候选项看板文件为当前目录下的board.json。脚本列表和数据来源:references/data-sources.md。 - macOS 没有
timeout命令;在 zsh 中,$var不会进行单词拆分,因此请在循环中使用bash -c或${=var}。全省范围的 Overpass 查询可能需要几分钟;请在后台运行。