关于 Stack Guardian
Stack Guardian 汇总家庭 AI 环境中节点、模型、GPU 和 tailnet 的状态,并依据连续运行记录为发现标注置信等级。它面向本地模型环境的维护者和编码 Agent,提供 CLI、MCP 服务、Prometheus 指标端点及 DeepSeek Harness 插件。
主要功能
- 01并行采集节点与模型状态
- 02检查 Ollama、兼容端点、GPU 和 tailnet
- 03按连续发现记录评定置信度
- 04提供需明确执行的类型化修复
- 05支持 CLI、MCP、HTTP 指标和 DSH 插件
适用场景
- 01定位多节点本地模型环境中的故障
- 02区分单次异常与持续问题
- 03让编码 Agent 只读查询堆栈状态
- 04通过 Prometheus 端点抓取指标
MCP 相关
stdio MCP 服务提供三个只读工具:stack_health、stack_snapshot 和 stack_explain,用于检查状态、获取快照及解释发现代码。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
3收录的工具列表 · 更新于 5 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| node | string | 否 | 单个节点名称;省略则检查全部节点 |
详细介绍
stack-guardian
mcp-name: io.github.LuminariSoftwares/stack-guardian
用于家庭 AI 技术栈的健康检查工具。它会收集节点快照(Ollama 或兼容 OpenAI 的端点、已加载的模型、NVIDIA GPU、tailnet 对等节点),针对快照运行小型 Python 规则,记住最近的运行记录,并报告带有置信等级的发现:单次采样最高为 LIKELY,同一发现连续出现两次则为 VERIFIED。之所以开发它,是因为在由多台机器组成的本地技术栈中,“模型运行很慢”可能有十几种原因,Agent 或用户应该得到经过分级、有证据支持的答案,而不是猜测。发现可以附带一种有类型的修复操作,由你主动执行,绝不会自动执行。它以 CLI、面向编码 Agent 的 MCP 服务、带有 Prometheus 指标的小型 HTTP 端点以及 DeepSeek Harness (DSH) 插件的形式提供。
使用一个状态文件,对 examples/nodes.json 运行两次:
# run 1
FAIL ollama.unreachable [gpu-box-2]: 1 Ollama endpoint(s) do not answer: http://100.64.0.2:11434 (LIKELY)
FAIL ollama.unreachable [home-server]: 1 Ollama endpoint(s) do not answer: http://100.64.0.3:11434 (LIKELY)
FAIL tailnet.peer_offline [home-server]: tailnet peer offline: home-server (LIKELY)
WARN model.expiring [gpu-box]: 1 loaded model(s) unload within 60s: qwen3:8b (LIKELY)
OK ollama.answering [gpu-box]: 1 endpoint(s) answer: http://127.0.0.1:11434
worst: FAIL
# run 2 (same state file)
FAIL ollama.unreachable [gpu-box-2]: 1 Ollama endpoint(s) do not answer: http://100.64.0.2:11434 (VERIFIED)
FAIL ollama.unreachable [home-server]: 1 Ollama endpoint(s) do not answer: http://100.64.0.3:11434 (VERIFIED)
FAIL tailnet.peer_offline [home-server]: tailnet peer offline: home-server (VERIFIED)
WARN model.expiring [gpu-box]: 1 loaded model(s) unload within 60s: qwen3:8b (VERIFIED)
OK ollama.answering [gpu-box]: 1 endpoint(s) answer: http://127.0.0.1:11434
worst: FAIL
这是运行 python examples/demo_report.py 得到的实际输出:使用随附的采集器和规则,gpu-box 上由 127.0.0.1 提供响应的 Ollama 存根、从未访问的两个占位 tailnet 地址,以及示例 nvidia-smi 和 tailscale 输出,因此在任何机器上打印的内容都相同。随附的规则只报告问题;OK 行来自脚本中的一条小型规则。如果此代码块与脚本不一致,测试就会失败。
置信等级的意义。 单次运行中的发现最高为 LIKELY;同一发现连续出现在两次运行中则为 VERIFIED;通过检查不进行分级。在家庭网络中,休眠的笔记本电脑、Wi-Fi 中断或重新加载的模型都可能有几秒钟看起来出了问题,因此一次异常采样会被报告为“可能存在问题”,只有持续存在的问题才会被报告为事实。
状态:0.3.0。仅使用标准库,Python 3.11+,无运行时依赖。
这是面向本地模型运行者的四款小型独立工具之一:参见 Guardian 系列。
与 StackGuardian(基础设施自动化公司)无关联。只是名称相同,项目无关。
快速开始(60 秒,离线)
macOS / Linux
pip install stack-guardian
curl -LO https://raw.githubusercontent.com/LuminariSoftwares/stack-guardian/main/examples/snapshot.json
curl -LO https://raw.githubusercontent.com/LuminariSoftwares/stack-guardian/main/examples/ctx.json
stack-guardian doctor --snapshot snapshot.json --ctx ctx.json
Windows(PowerShell),或任何你不想动系统 Python 的环境
pipx install stack-guardian
curl.exe -LO https://raw.githubusercontent.com/LuminariSoftwares/stack-guardian/main/examples/snapshot.json
curl.exe -LO https://raw.githubusercontent.com/LuminariSoftwares/stack-guardian/main/examples/ctx.json
stack-guardian doctor --snapshot snapshot.json --ctx ctx.json
pipx 会将它安装到独立的虚拟环境中,并添加到 PATH 中(如果尚未安装 pipx,可运行 pip install pipx)。uvx stack-guardian doctor --snapshot snapshot.json 无需安装即可运行。
示例快照会让所有随附规则各触发一次,因此你无需接触真实技术栈,就能看到每种发现类型。由于示例中包含 FAIL 发现,该命令会以 2 退出;这是预期结果。每行末尾都会显示置信等级——单次运行最高为 (LIKELY),同一发现第二次出现时为 (VERIFIED)。
接下来,将它指向你自己的机器:
stack-guardian init # writes nodes.json for this machine; never overwrites one
stack-guardian doctor --nodes nodes.json
init 会探测 http://127.0.0.1:11434,检查 Ollama 是否有响应;如果 tailscale 位于 PATH 中,还会列出你的 tailnet 对等节点,并将其作为注释掉的候选项,以便你将其移入文件。之后可手动编辑;配置格式见 examples/nodes.json 和功能说明。
如果从仓库克隆开始(用于编写规则或运行测试):
git clone https://github.com/LuminariSoftwares/stack-guardian.git
cd stack-guardian
python -m venv .venv
.venv\Scripts\activate # Windows; macOS/Linux: source .venv/bin/activate
pip install -e ".[test]" # drop [test] if you only want to run it, not test it
stack-guardian doctor --snapshot examples/snapshot.json --ctx examples/ctx.json
python -m pytest -q
架构
flowchart LR
nodes["nodes.json"] --> collect
subgraph collect["collect: one snapshot, all nodes in parallel"]
direction TB
ol["Ollama /api/tags, /api/ps<br/>OpenAI-compatible /v1/models"]
gpu["nvidia-smi<br/>(local node only)"]
ts["tailscale status --json"]
end
collect --> snap[("snapshot dict")]
snap --> rules["checks.d/*.py rules<br/>run concurrently;<br/>a crash becomes check.crashed"]
rules --> grade["state.grade<br/>LIKELY until seen twice, then VERIFIED"]
hist[("state.json<br/>last 5 runs per node")] <--> grade
grade --> cli["CLI: doctor<br/>exit 0 / 1 / 2"]
grade --> mcp["MCP stdio server<br/>read-only, never records"]
grade --> http["serve: /snapshot, /metrics"]
grade -.->|"finding.fix"| fix["doctor --fix ID<br/>dry run unless --apply;<br/>snapshot + audit line"]
| 模块 | 作用 |
|---|---|
collect.py、multinode.py、parsers.py | 在统一的截止时间内并行探测每个节点;将 Ollama、OpenAI-compatible、nvidia-smi 和 tailscale 的输出解析为一个快照字典。无法访问的端点会作为数据处理,不会引发异常。 |
core.py、finding.py、checks.d/ | 加载规则文件、并发运行规则,并以固定结构(code, severity, level, node, summary, evidence, try, confidence, fix)构建发现结果。 |
state.py | 保存每个节点最近的运行记录,并根据连续运行次数评估置信度。 |
fixes.py | 三种类型化修复操作、对应的试运行计划、快照和审计记录。 |
cli.py、mcp_server.py、serve.py | 同一个诊断器的三个前端。 |
设计决策
每项设计及其替代方案都记录在 docs/adr/ 中。
- 仅使用标准库(ADR 0001)。
pip install不会拉取其他依赖,因此可以安装在任何装有 Python 3.11 的机器上。权衡:HTTP 客户端、JSON-RPC 循环和 Prometheus 渲染器均为手写代码,需要在此处进行测试。 - 规则是文件夹中的普通 Python 文件(ADR 0002)。规则是一个函数
(snapshot, ctx) -> finding | list | None;若规则引发异常,则会变成check.crashedWARN,因此有缺陷的规则不会报告堆栈故障。权衡:规则会以你的权限在进程内运行;只加载你信任的规则文件夹。 - 根据历史记录而非单次采样评估置信度(ADR 0003)。单次运行的置信度最高为
LIKELY;连续两次运行异常才会达到VERIFIED。权衡:真实故障需要第二次运行后才能标记为VERIFIED,且历史记录保存在本地文件中。 - 类型化修复,默认试运行(ADR 0004)。仅有三种操作,规则绝不会传入 shell 字符串;未指定
--apply时不会更改任何内容,每次应用修复都会留下快照和审计记录。权衡:三种操作之外的所有事项都必须手动处理。 - 面向 Agent 的接口为只读(ADR 0005)。MCP 服务和 HTTP 端点不会执行修复,也不会写入运行历史;除非另有指定,
serve只绑定到回环地址。权衡:Agent 可以诊断问题,但必须将修复交由人员处理。
面向编码 Agent
- MCP 服务(任何 MCP 客户端):
stack-guardian-mcp通过 stdio 使用 MCP,提供三个只读工具:stack_health、stack_snapshot和stack_explain。客户端配置和工具参考请参阅 MCP 服务。 - DSH 插件(
npm install dsh-stack-guardian,源码位于dsh/,需要 Node 20+):当诊断器报告 WARN 或 FAIL 时,在 DeepSeek Harness 会话开头添加一行提示,否则不作处理。它会运行stack-guardian doctor --json --quiet,因此请在 Harness 环境中将STACK_GUARDIAN_NODES设为你的节点文件。 - 监视和抓取:
stack-guardian doctor --watch 30 --json会针对状态发生变化(新增、已解决、严重性变化)的发现结果各打印一个 JSON 对象,供 Agent 持续读取;stack-guardian-serve --nodes FILE也会以 Prometheus 文本格式响应GET /metrics。
MCP 服务
stack-guardian-mcp(也可写作 stack-guardian mcp)通过 stdio 使用 MCP(JSON-RPC 2.0,协议版本 2024-11-05)。它需要一个节点文件(examples/nodes.json);通过 --nodes FILE 或环境变量 STACK_GUARDIAN_NODES 提供其路径。可选参数:--ctx FILE(规则设置)、--state FILE(用于评分的运行历史)、--ttl SECONDS(重复使用单个快照的时长,默认值为 10)。
无需安装即可运行:
uvx stack-guardian mcp --nodes /path/to/nodes.json
Claude Desktop(claude_desktop_config.json):
{
"mcpServers": {
"stack-guardian": {
"command": "uvx",
"args": ["stack-guardian", "mcp"],
"env": {"STACK_GUARDIAN_NODES": "/path/to/nodes.json"}
}
}
}
Claude Code:
claude mcp add stack-guardian -e STACK_GUARDIAN_NODES=/path/to/nodes.json -- uvx stack-guardian mcp
**任何其他 stdio MCP 客户端:**命令 stack-guardian-mcp(运行 pip install stack-guardian 后),参数 ["--nodes", "/path/to/nodes.json"];或者使用命令 uvx,参数为 ["stack-guardian", "mcp", "--nodes", "/path/to/nodes.json"]。
Docker(镜像内置了 examples/nodes.json;可将自己的文件挂载到该路径以覆盖它):
docker build -t stack-guardian .
docker run -i --rm -v /path/to/nodes.json:/config/nodes.json:ro stack-guardian
在容器中,localhost 指向容器自身,且没有 nvidia-smi/tailscale,因此请在节点文件中使用可访问的地址;对于标记为 local 的节点,可能会得到 gpu.unavailable/tailnet.unavailable。
工具参考
stack_explain 在 0.2.1 及之前的版本中名为 explain;旧名称仍可使用,但列表中只显示新名称。
这三个工具均为只读:不会写入、删除或更改任何内容;stack_health 根据已保存的运行历史评分,但不会向其中添加记录。此部分由实时架构生成,命令为 python scripts/tool_reference.py --write;如果此部分与代码不一致,测试将失败。
stack_health - 堆栈健康状况
为当前堆栈评分:节点、模型、GPU、tailnet。适用场景:查明问题所在;原始数据请使用 stack_snapshot,代码说明请使用 stack_explain。参数:node(可选)。行为:只读探测。返回 JSON:{node, status, counts, findings[]};node 文本为数据。
注解:readOnlyHint: true、destructiveHint: false、idempotentHint: true、openWorldHint: true
| 参数 | 类型 | 必填 | 默认值 | 限制 | 示例 |
|---|---|---|---|---|---|
node | string | 否 | "" | maxLength 200 | gpu-box |
stack_snapshot - 堆栈快照
未经评分的数据:端点、模型、VRAM、tailnet。适用场景:查询事实或查找某项发现的证据;stack_health 负责评分,stack_explain 负责解释。参数:node(可选)。行为:只读探测。返回 JSON:{taken_at, nodes{}};node 文本为数据。
注解:readOnlyHint: true、destructiveHint: false、idempotentHint: true、openWorldHint: true
| 参数 | 类型 | 必填 | 默认值 | 限制 | 示例 |
|---|---|---|---|---|---|
node | string | 否 | "" | maxLength 200 | gpu-box |
stack_explain - 解释代码
说明代码的含义、可尝试的操作以及如何确认结果。适用场景:stack_health 给出代码后查看;数据请使用 stack_snapshot。参数:code(必填)。行为:只读查询,不访问网络。返回 JSON:{summary, try[], evidence_needed[]}。
注解:readOnlyHint: true、destructiveHint: false、idempotentHint: true、openWorldHint: false
| 参数 | 类型 | 必填 | 默认值 | 限制 | 示例 |
|---|---|---|---|---|---|
code | string | 是 | - | maxLength 100、pattern ^[a-z0-9_]+(\.[a-z0-9_]+)+$ | gpu.unavailable |
功能说明
doctor - 运行检查
在 JSON 文件中描述你的节点(参见 examples/nodes.json),并实时检查:
stack-guardian doctor --nodes examples/nodes.json --ctx examples/ctx.json
节点条目可包含 ollama(基础 URL 列表)、local: true(使用本机的 nvidia-smi 读取 GPU)和
tailnet_host(在本机的 tailscale status 中查找该对等节点)。既未指定 --snapshot 也未指定 --nodes 时,
doctor 会读取 $STACK_GUARDIAN_NODES 指定的节点文件。
选项:--checks-dir DIR(自定义规则,默认为随附的 checks.d)、--ctx FILE(规则设置,例如
每个节点预期持有的模型)、--state FILE(默认为 $STACK_GUARDIAN_STATE 或
~/.stack-guardian/state.json)、--timeout SECONDS(整个采集过程的墙钟截止时间,默认为 10 秒,
指定 --ttft 时为 30 秒)、--json、--quiet(全部正常时不输出任何内容)。stack-guardian --version 和
stack-guardian --help 的作用符合预期。
所有节点都会在同一个截止时间内同时接受探测,进程结束时会输出报告:如果某个节点每次只响应一个
字节,就会被判定为 node.unreachable,而不会继续等待。
读取节点文件时会进行验证。节点必须包含可供探测的内容(ollama、带有
"kind": "openai" 的 endpoints、local: true 或 tailnet_host),URL 必须带有协议;否则会报用法错误
(退出码 3),并指出节点名称,而不是给出貌似确定的错误答案。如果应为列表的位置填入了单个 URL 字符串,也会接受,但会在 stderr 上提示一次。以下划线开头的键会被忽略,因此文件可以包含注释和候选节点;"_options": {"timeout_s": 20} 可设置该文件的截止时间。
人类可读的输出会在每行末尾标注发现结果的置信度——运行一次时为 (LIKELY),同一发现结果出现两次后为 (VERIFIED)——并且 worst: X 始终是最后一行。--json 会输出
{"schema": 1, "findings": [...], "worst": "..."}。
退出码:0 表示全部为 OK/INFO,1 表示 WARN,2 表示 FAIL,3 表示用法错误,4 表示 doctor 本身崩溃。
随附规则:node.unreachable、ollama.unreachable、model.not_loaded、model.expiring、model.slow_ttft、
vram.unattributed、gpu.unavailable、gpu.parse_degraded、tailnet.unavailable、tailnet.peer_offline、
tailnet.relayed。每条规则都会针对每个受影响的节点生成一条发现结果。规则引发异常时会产生 check.crashed WARN——有缺陷的规则绝不会报告堆栈故障。
LM Studio、vLLM、llama.cpp server。 将节点设为 "kind": "openai",并在 endpoints 下列出其基础 URL。
系统会从 GET /v1/models(以及服务器提供该接口时的 GET /v1/models/<id>)读取数据,并转换为与 Ollama 端点相同的格式,因此上述所有规则均适用;服务器列为未加载的模型不会被视为已加载。
{"gpu-box": {"kind": "openai", "endpoints": ["http://127.0.0.1:1234"]}}
model.expiring(WARN):已加载的 Ollama 模型,其 /api/ps 中的 expires_at 距快照时间不足 60 秒;
若 /api/ps 不可用,则显示 INFO。可在 --ctx 中通过 "model_expiring_s": 120 更改时间窗口。
--watch N 每隔 N 秒重新运行 doctor,并仅输出状态发生变化的发现结果,每条都带有时间戳。按 Ctrl+C 会以退出码 0 退出,并输出一行摘要。使用 --json 时,每次变化都会在 stdout 上输出一个 JSON 对象。
stack-guardian doctor --nodes examples/nodes.json --watch 30
--ttft 会对每个 Ollama 端点上已加载的模型发送一次生成 1 个 token 的请求,并在快照中为该模型记录 ttft_ms。此操作会触发一次生成,因此只有在传入该选项时才会运行,并且需要指定 --nodes。探测会保留每个模型原有的卸载时间。model.slow_ttft(INFO)会在耗时超过 2000 毫秒时触发;可在 --ctx 中通过 "ttft_slow_ms": 1500 更改阈值。
stack-guardian doctor --nodes examples/nodes.json --ttft
doctor --fix ID - 执行某个发现项的类型化修复
规则可以为发现项附加 fix={"action": ..., "args": {...}}。操作恰好有三种,且绝不会使用原始
shell 字符串:
| action | 功能 | 所需参数 |
|---|---|---|
unload_model | 向 Ollama /api/generate 发送 keep_alive: 0 | node、url、model |
restart_lane | 运行你为该通道声明的 argv 列表 | 在 --config 中声明的 lane |
set_env | 将 NAME=value 写入 <state folder>/env,并为进程设置该值 | name、value |
stack-guardian doctor --checks-dir examples/checks.d --snapshot examples/snapshot.json --fix ollama.stuck --config examples/lanes.json
这是一次试运行:只打印计划,不做任何更改。添加 --apply 才会执行。应用修复时,会先将快照保存到
<state folder>/snapshots/,然后执行修复,最后向 <state folder>/fixes.jsonl 追加一行 JSON
(使用 --audit FILE 可更改其位置)。set_env 的值不会写入审计记录,只记录其长度。ID 是发现项
代码;如果多个节点报告相同代码,则使用 code@node。使用 --fix 时,退出代码由修复操作决定:计划或
成功时为 0,拒绝或失败时为 1,用法错误时为 3。
其他命令
-
stack-guardian init [--out nodes.json] [--ollama URL]为这台机器写入一个初始节点文件:它会探测 本地 Ollama,将 tailnet 对等节点列为注释掉的候选项;如果文件已存在,则拒绝覆盖并以退出代码3退出。 -
stack-guardian snapshot --nodes FILE [--ttft] [--timeout SECONDS]打印规则读取的原始快照。 -
stack-guardian-serve --nodes FILE [--ctx FILE] [--port 8788] [--cache SECONDS]在GET /snapshot提供最新快照,并在GET /metrics提供 Prometheus 指标(只读;除非传入--host H --allow-remote,否则仅限环回地址)。它是一个抓取目标,而非集群协议:stack-guardian 的其他部分 不会读取它。每个请求都会收集一份新快照;如果抓取间隔短于节点响应时间,--cache SECONDS(默认值为0,即关闭)会在指定时长内复用同一份快照。它没有身份验证:只能绑定到 localhost 或 tailnet IP。 -
同一服务还会以 Prometheus 文本格式响应
GET /metrics,并基于最新快照运行随附规则:stack_guardian_finding{code,severity,node}(发现项存在时为 1,解决后为 0),stack_guardian_worst_severity(0 表示 OK,1 表示 INFO,2 表示 WARN,3 表示 FAIL),以及stack_guardian_last_run_timestamp。curl http://127.0.0.1:8788/metrics -
stack-guardian-mcp --nodes FILE [--ctx FILE] [--state FILE] [--ttl SECONDS]:请参阅 MCP 服务。
编写规则
from stack_guardian import finding as F
def ollama_up(snapshot, ctx):
if not snapshot["nodes"]["gpu-box"].get("reachable"):
return F.make_finding("ollama.unreachable", "missing", "FAIL", "gpu-box", "Ollama does not answer")
return None
CHECKS = [("ollama.up", ollama_up)]
将文件放入某个文件夹,并将 --checks-dir 指向该文件夹。带修复的完整示例见
examples/checks.d/20_ollama_fix.py。规则也可以返回发现项列表,
每个节点对应一项。
示例
| 文件 | 说明 |
|---|---|
examples/nodes.json | 三个节点:一个带 GPU 的本地节点,以及两个通过 tailnet 连接的远程节点 |
examples/ctx.json | 规则设置:gpu-box-2 应保留的模型 |
examples/snapshot.json | 一份离线快照,所有随附规则都会触发一次,可用于尝试 doctor 和 --fix |
examples/lanes.json | restart_lane 可运行的通道 |
examples/checks.d/20_ollama_fix.py | 一个发现项附带修复操作的自定义规则 |
examples/demo_report.py | 打印本 README 顶部的两次运行报告:在 127.0.0.1 上运行一个 Ollama 存根,不使用其他网络 |
故障排查
通过查找代码——同样的文本 stack_explain 会提供给 Agent:
| 你看到的内容 | 含义 | 首先尝试 |
|---|---|---|
node.unreachable | 节点未在截止时间内响应,或采集器引发了异常 | 检查机器是否已开机;如果只是响应慢,使用 --timeout 30 或 "_options": {"timeout_s": 30} |
ollama.unreachable | 端点本身拒绝了请求或超时 | 在这台机器上运行 curl http://HOST:11434/api/version;检查端口,以及 Ollama 是否监听了回环地址以外的地址(OLLAMA_HOST) |
model.not_loaded | --ctx 预期的模型当前未驻留 | 发送一次简短的生成请求来加载它,或从 --ctx 中移除该预期 |
model.expiring | 已加载的模型会在 60 秒内卸载(提示:缺少 /api/ps,因此无法确认) | 发送带有更长 keep_alive 的请求,或在该节点上设置 OLLAMA_KEEP_ALIVE |
model.slow_ttft | --ttft 探测从发出请求到收到首个令牌耗时超过 2000 ms | 检查模型是否能装入 VRAM,以及该 GPU 上是否有其他生成任务正在运行 |
vram.unattributed | VRAM 正在被占用,但无法由列出的进程解释 | 运行 nvidia-smi 并查看计算应用;在 Windows 上,一些进程会显示 [N/A],因此无法确定归属 |
gpu.unavailable | nvidia-smi 不存在,或运行失败——检测结果会说明具体原因 | 仅适用于 NVIDIA;如果已安装,请手动运行 nvidia-smi 并修复驱动 |
gpu.parse_degraded | nvidia-smi 输出了一行包含 [N/A] 字段的 GPU 信息,因此该显卡未出现在报告中 | 手动运行查询(证据中会引用该行);更新驱动 |
tailnet.unavailable | tailscale 不在 PATH 中,或 tailscale status 运行失败 | 不在 tailnet 上?从该节点移除 tailnet_host;否则,启动 tailscaled 或登录 |
tailnet.peer_offline | tailnet 显示该对等端处于离线状态 | 检查机器是否已启动,并在其上运行 tailscale status |
tailnet.relayed | 只能通过 DERP 中继访问该对等端 | 检查 UDP 41641 和防火墙;在两端运行 tailscale netcheck |
check.crashed | 其中一个规则文件引发了异常 | 证据中包含异常信息;修复或移除该文件 |
按症状排查:
| 你看到的内容 | 原因 |
|---|---|
stack-guardian: usage: ... nothing to probe | nodes 文件中的某个节点没有端点、没有 local: true,也没有 tailnet_host。以前它会报告 worst: OK。 |
stack-guardian: usage: ... "kind": "openai" | 该节点列出了 endpoints,但未标记为兼容 OpenAI 的节点 |
每条检测结果都显示 (LIKELY) | 置信度来自历史记录:使用同一个 --state 文件运行两次 |
MCP 服务始终不显示 VERIFIED | 这是设计如此;它会根据已保存的历史记录进行评级,但不会向其中添加记录;让 CLI 或 --watch 来积累历史记录 |
doctor 在示例快照上以状态码 2 退出 | 示例的目的正是让每条规则都触发一次 |
哪些信息会离开本机,哪些内容会被写入
- **发出:**仅向节点文件中指定的基础 URL 发送 HTTP(S) 请求(
/api/version、/api/tags、/api/ps,或 OpenAI 兼容节点的/v1/models);使用--ttft时,会为每个已加载模型生成一次 1-token 内容。不发送凭据,会跟随重定向,除此之外不会向任何地方发送数据:没有遥测、更新检查或分析数据。nvidia-smi和tailscale status --json都在本地运行。 - **接收:**运行时不会下载或安装任何内容。此软件包没有运行时依赖项。
- **写入:**状态目录
$STACK_GUARDIAN_STATE或~/.stack-guardian/,权限设为0700。其中包含state.json(每个节点最近 5 次运行的代码和级别,不含测量数据);仅在使用--fix ... --apply后,才会包含fixes.jsonl(每项已应用修复对应一行审计记录)和snapshots/(修复前立即创建的快照)。set_env还会写入env。这些文件的权限均设为0600;set_env的值绝不会写入审计记录,只记录其长度。doctor --json、snapshot和 MCP 服务除了各自的输出外,不会写入任何内容。 - **显示:**快照包含你的节点名称、模型名称、VRAM 数据、GPU 进程名称和 tailnet 状态。这些信息会由
stack-guardian-serve提供,并由 MCP 客户端接收,因此应像对待nvidia-smi输出一样谨慎处理。
限制
以下是它不会执行的操作,避免你对此感到意外:
- **仅支持 NVIDIA GPU,且只支持运行 stack-guardian 的机器上的 GPU。**GPU 数据来自标记为
"local": true的节点上的nvidia-smi。远程节点只会报告端点、模型和 tailnet 状态,不会报告 VRAM。此软件包不会读取其他机器的/snapshot,因此无法将远程节点的 GPU 数据纳入此报告:也请在那台机器上运行stack-guardian,或使用 Prometheus 抓取其stack-guardian-serve的/metrics。不支持 AMD、Intel 或 Apple GPU。 - **tailnet 状态仅反映本机视角。**对等节点信息来自本地的
tailscale status --json;某个对等节点对你可能处于离线状态,但对另一个节点可能处于在线状态。 - **
VERIFIED需要运行两次。**MCP 服务从不记录运行记录,因此除非 CLI(或--watch)已在同一个状态文件中积累历史记录,否则它最多只会报告LIKELY。 - **
stack-guardian-serve不提供身份验证。**它是只读的,默认仅监听环回地址;不适用于开放互联网。 - MCP 仅支持通过 stdio 通信,协议版本为
2024-11-05:结果为 JSON 文本内容,不包含outputSchema或structuredContent。 - **规则在进程内运行。**规则目录中的内容是代码;请仅将
--checks-dir指向你信任的规则。 --ttft会为每个已加载模型实际生成一次内容,因此默认关闭。
测试方式
pip install -e ".[test]"
python -m pytest -q
- 每个模块都包含一个带计数的
--selftest(纯函数、注入的 HTTP 和命令运行器,不访问网络);测试套件会逐一运行这些自测。 - 集成测试会在子进程中,通过 stdio 驱动真实的 CLI 和 MCP 服务,包括工具列表及其注释;并会严格按照本 README 中的示例运行
examples/。 - 如果任何 MCP 工具或参数缺少描述、类型、示例、默认值或约束,如果已发布的发现代码没有对应的
stack_explain条目,或上述工具参考文档已过时,tests/test_tool_definitions.py就会失败。 tests/test_tools_list_budget.py会启动真实的 MCP 服务;如果整个tools/list负载超过其 token 预算,就会失败,因为每次请求都会发送这些定义。- CI 会在 Ubuntu、Windows 和 macOS(Python 3.11)上运行测试套件,也会在 Ubuntu 上使用 3.12 和 3.13 运行;构建 wheel 并在干净的 virtualenv 中运行(因此,缺少规则的发布版本会导致失败);构建 Docker 镜像并列出其工具;对 DSH 插件进行语法检查;并扫描所有受跟踪文件以检查隐私问题。
贡献与安全
欢迎提交拉取请求;CONTRIBUTING.md 介绍了环境设置、项目风格,以及三条重要规则(先观察测试失败、不得新增运行时依赖、工具定义的令牌预算)。
发现了可利用的漏洞?请通过仓库的 Security 选项卡私下报告,不要提交公开议题:
SECURITY.md 说明了报告方式,并列出了此工具按设计实现的行为(规则是代码、会获取节点 URL、serve 没有身份验证)。
致谢
没有复制其他项目的代码。线路格式遵循其公开规范:Model Context Protocol(通过 stdio 传输 JSON-RPC、工具注释)和
Prometheus text exposition format。数据来自以下项目的文档接口:Ollama、nvidia-smi 和
tailscale status --json。
guardian 系列
为运行本地模型的用户打造的四款小型 MIT 许可工具。每款工具各司其职,彼此不共享代码,也都能独立使用。
| 工具 | 能解答的问题 |
|---|---|
| code-guardian | 运行或合并你没有编写的代码前:安全吗?能正常运行吗?有什么遗漏?通过静态扫描提供三项评分,并深入分析 Python。 |
| context-guardian | 让长时间运行的本地模型会话保持在上下文窗口内:它是一个会在窗口填满前压缩历史记录的代理,并提供用于搜索归档内容的工具。 |
| tool-guardian | 通过少量工具路由多个 MCP 服务,避免它们的定义占满上下文窗口。 |
| stack-guardian | 我的家庭 AI 技术栈运行正常吗?可检查 Ollama / OpenAI 兼容节点、NVIDIA GPU 和 Tailscale 对等设备,并为每项发现标注置信度等级。 |
许可证
MIT。请参阅 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。