vmware-debug 1.8.5__tar.gz → 1.8.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/PKG-INFO +26 -39
  2. vmware_debug-1.8.7/README-CN.md +45 -0
  3. vmware_debug-1.8.7/README.md +62 -0
  4. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/RELEASE_NOTES.md +31 -0
  5. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/pyproject.toml +1 -1
  6. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/server.json +2 -2
  7. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/skills/vmware-debug/SKILL.md +6 -12
  8. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/skills/vmware-debug/references/agent-guardrails.md +1 -38
  9. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/skills/vmware-debug/references/capabilities.md +0 -5
  10. vmware_debug-1.8.7/skills/vmware-debug/references/setup-guide.md +49 -0
  11. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/_scores.json +14 -16
  12. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/conftest.py +6 -23
  13. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/test_entity_reachability.py +6 -36
  14. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/test_tool_manifest_budget.py +3 -42
  15. vmware_debug-1.8.7/tests/eval/regression/test_tool_annotations.py +42 -0
  16. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/__init__.py +1 -1
  17. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/mcp_server/server.py +2 -19
  18. vmware_debug-1.8.5/README-CN.md +0 -79
  19. vmware_debug-1.8.5/README.md +0 -75
  20. vmware_debug-1.8.5/skills/vmware-debug/references/setup-guide.md +0 -90
  21. vmware_debug-1.8.5/tests/eval/regression/test_read_only_mode.py +0 -158
  22. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/.gitignore +0 -0
  23. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/SECURITY.md +0 -0
  24. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/skills/vmware-debug/references/cli-reference.md +0 -0
  25. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/skills/vmware-debug/references/event-envelope.md +0 -0
  26. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/skills/vmware-debug/references/routing.md +0 -0
  27. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/__init__.py +0 -0
  28. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/__init__.py +0 -0
  29. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/_family.py +0 -0
  30. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/_scoring.py +0 -0
  31. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/_skill.py +0 -0
  32. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/test_error_actionability.py +0 -0
  33. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/capability/test_tool_description_quality.py +0 -0
  34. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/regression/__init__.py +0 -0
  35. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/regression/test_capability_grader.py +0 -0
  36. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/regression/test_debug_regressions.py +0 -0
  37. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/regression/test_declared_environment.py +0 -0
  38. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/eval/regression/test_result_envelope.py +0 -0
  39. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/test_safe_error_passthrough.py +0 -0
  40. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/tests/test_timeline.py +0 -0
  41. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/uv.lock +0 -0
  42. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/cli.py +0 -0
  43. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/envelope.py +0 -0
  44. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/mcp/__init__.py +0 -0
  45. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/mcp/tools.py +0 -0
  46. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/mcp_server/__init__.py +0 -0
  47. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/ops/__init__.py +0 -0
  48. {vmware_debug-1.8.5 → vmware_debug-1.8.7}/vmware_debug/ops/timeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vmware-debug
3
- Version: 1.8.5
3
+ Version: 1.8.7
4
4
  Summary: VMware diagnostic brain — read-only incident triage, log/event correlation, and root-cause routing across the VMware skill family
5
5
  Author-email: Wei Zhou <wei-wz.zhou@broadcom.com>
6
6
  License-Expression: MIT
@@ -40,8 +40,6 @@ advisor/executor split.
40
40
  See [`skills/vmware-debug/SKILL.md`](skills/vmware-debug/SKILL.md) for the full
41
41
  methodology, the event-envelope contract, and symptom routing.
42
42
 
43
- - **Read-only by design — and provable** (v1.8.0): both MCP tools are read, none write; set `VMWARE_READ_ONLY=true` (or the per-skill `VMWARE_DEBUG_READ_ONLY`) and the family read-only gate verifies that at startup instead of taking the docs' word for it — env vars are the only switch here, this skill has no config file. See [Read-Only Mode](#read-only-mode).
44
-
45
43
  ## MCP tools
46
44
 
47
45
  | Tool | What |
@@ -49,44 +47,33 @@ methodology, the event-envelope contract, and symptom routing.
49
47
  | `incident_timeline` | [READ] Correlate pre-fetched events → timeline + spikes + ranked hypotheses + next-check ideas |
50
48
  | `list_symptom_categories` | [READ] List recognised symptom categories + what to check for each |
51
49
 
52
- ## Read-Only Mode
53
-
54
- vmware-debug is read-only by design — both MCP tools carry the `[READ]` marker, take no
55
- credentials, and make no network calls at all; they only correlate event dicts the
56
- calling agent has already fetched with the other skills' read tools. Since v1.8.0 that
57
- is **provable rather than merely documented**: set `VMWARE_READ_ONLY=true` and the
58
- family read-only gate enumerates the registry at startup and verifies that zero write
59
- tools are exposed — structural, not a prompt instruction a model can ignore. **Off by
60
- default.** Fail-closed: if the mode is requested but cannot be guaranteed, the server
61
- refuses to start rather than running open.
62
-
63
- The same variable is family-wide: one env var also strips every write tool from the
64
- write-capable siblings (aiops, storage, vks, nsx, ...), so a whole-estate read-only
65
- posture is a single setting.
66
-
67
- ```json
68
- {
69
- "mcpServers": {
70
- "vmware-debug": {
71
- "command": "vmware-debug",
72
- "args": ["mcp"],
73
- "env": {
74
- "VMWARE_READ_ONLY": "true"
75
- }
76
- }
77
- }
78
- }
50
+ ## Offline / Air-Gapped Install (from source)
51
+
52
+ This project uses the modern PEP 517 build system (hatchling), so there is **no
53
+ `setup.py`** by design — that is expected, not a missing file. If you cloned the
54
+ source and hit `ERROR: File "setup.py" or "setup.cfg" not found ... editable mode
55
+ currently requires a setuptools-based build`, your `pip` is older than 21.3 and
56
+ cannot do an *editable* (`-e`) install with a non-setuptools backend. Editable
57
+ mode is a developer convenience, not needed to run the tool — do one of:
58
+
59
+ ```bash
60
+ # From the source tree — a normal (non-editable) install builds a wheel:
61
+ pip install . # NOT pip install -e .
62
+
63
+ # ...or upgrade pip first, and editable works too:
64
+ pip install --upgrade pip && pip install -e .
79
65
  ```
80
66
 
81
- - **Per-skill override**: `VMWARE_DEBUG_READ_ONLY` beats the family-wide
82
- `VMWARE_READ_ONLY`. vmware-debug has no `config.yaml`, so the env vars are the only
83
- switch. Precedence: per-skill env → family env → off.
84
- - **Classification**: this skill registers its tools through a `build_server()` factory,
85
- so the gate classifies from the `[READ]`/`[WRITE]` docstring marker rather than from
86
- MCP annotations. Anything not provably read-only is treated as a write.
87
- - **Startup log**: nothing is logged as withheld because nothing is — the gate's empty
88
- result *is* the assertion (write-capable siblings log
89
- `Read-only mode active ... withheld N write tool(s)` instead).
67
+ For a **truly air-gapped host**, build the wheels on a connected machine and copy
68
+ them over — the target then needs no network:
69
+
70
+ ```bash
71
+ # On a connected machine, collect this package + its dependencies as wheels:
72
+ pip wheel . -w dist # → dist/*.whl (or: uv build, for just this package)
73
+
74
+ # Copy dist/ to the air-gapped host, then install offline:
75
+ pip install --no-index --find-links dist vmware-debug
76
+ ```
90
77
 
91
78
  ## License
92
79
 
@@ -0,0 +1,45 @@
1
+ <!-- mcp-name: io.github.zw008/vmware-debug -->
2
+
3
+ # VMware Debug(中文)
4
+
5
+ > **声明**:本项目为社区维护的开源项目,**与 VMware, Inc. 或 Broadcom Inc. 无任何隶属、
6
+ > 背书或赞助关系。** "VMware"、"vSphere" 为 Broadcom 商标。源码以 MIT 许可证公开可审计。
7
+
8
+ VMware skill 家族的**诊断大脑**。你给出症状(报错、日志、变慢的 VM),它来跑系统化排查:
9
+ 把其它 skill 取到的事件关联成一条时间线、检测突刺、给根因假设排序,并告诉你下一步该查什么。
10
+ **只读**——从不修改任何东西,也从不执行修复。修复一律路由给 vmware-aiops(单步)或
11
+ vmware-pilot(多步、带审批门控),完全复刻 vmware-harden → vmware-pilot 的「顾问/执行」分工。
12
+
13
+ ## 配套 Skill
14
+
15
+ | 需求 | Skill |
16
+ |---|---|
17
+ | 故障关联 / 根因 | **vmware-debug**(本项目) |
18
+ | 集中日志检索 | vmware-log-insight(把 `log_search` 结果喂给它) |
19
+ | vCenter 事件与告警 | vmware-monitor |
20
+ | 指标 / 异常 | vmware-aria |
21
+ | 执行修复 | vmware-aiops(单步)/ vmware-pilot(多步门控) |
22
+
23
+ ## 安装
24
+
25
+ ```bash
26
+ uv tool install vmware-debug
27
+ vmware-debug categories # 看它能诊断哪些症状类别
28
+ ```
29
+
30
+ ## MCP 工具(2 个,全只读)
31
+
32
+ - `incident_timeline`:把已取到的事件关联成 时间线 + 突刺 + 排序后的根因假设 + 下一步检查建议
33
+ - `list_symptom_categories`:症状类别及对应的排查路由(不知道查什么时用它)
34
+
35
+ **事件信封**:`{ts, source, severity, entity, text, fields}`。agent 把各源事件归一成此形状再交给
36
+ debug;debug 因此与其它包零运行时依赖。
37
+
38
+ ## 安全
39
+
40
+ 结构上只读、离线、无凭据:不连任何 vCenter/NSX/Aria,没有可破坏面,也没有秘密可泄露。
41
+ 详见 [SECURITY.md](SECURITY.md)。
42
+
43
+ ## 许可证
44
+
45
+ MIT。
@@ -0,0 +1,62 @@
1
+ <!-- mcp-name: io.github.zw008/vmware-debug -->
2
+
3
+ # VMware Debug
4
+
5
+ > ⚠️ **Work in progress** — the core (event correlation engine, MCP tools, CLI)
6
+ > is built and tested; README, `server.json`, full reference docs, and packaging
7
+ > polish are still landing. Not yet published to PyPI.
8
+
9
+ > **Disclaimer**: Community-maintained open-source project, **not affiliated with,
10
+ > endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** "VMware" and
11
+ > "vSphere" are trademarks of Broadcom. Source is publicly auditable under the MIT
12
+ > license.
13
+
14
+ The diagnostic brain of the VMware skill family. You bring the symptom (an error,
15
+ a log dump, a slow VM); this skill runs a systematic investigation, correlates
16
+ events from the other skills into one timeline, ranks root-cause hypotheses, and
17
+ tells you what to check next. It is **read-only** — it never changes anything and
18
+ never executes fixes. Remediation is routed to `vmware-aiops` (single op) or
19
+ `vmware-pilot` (multi-step, gated), mirroring the `vmware-harden → vmware-pilot`
20
+ advisor/executor split.
21
+
22
+ See [`skills/vmware-debug/SKILL.md`](skills/vmware-debug/SKILL.md) for the full
23
+ methodology, the event-envelope contract, and symptom routing.
24
+
25
+ ## MCP tools
26
+
27
+ | Tool | What |
28
+ |---|---|
29
+ | `incident_timeline` | [READ] Correlate pre-fetched events → timeline + spikes + ranked hypotheses + next-check ideas |
30
+ | `list_symptom_categories` | [READ] List recognised symptom categories + what to check for each |
31
+
32
+ ## Offline / Air-Gapped Install (from source)
33
+
34
+ This project uses the modern PEP 517 build system (hatchling), so there is **no
35
+ `setup.py`** by design — that is expected, not a missing file. If you cloned the
36
+ source and hit `ERROR: File "setup.py" or "setup.cfg" not found ... editable mode
37
+ currently requires a setuptools-based build`, your `pip` is older than 21.3 and
38
+ cannot do an *editable* (`-e`) install with a non-setuptools backend. Editable
39
+ mode is a developer convenience, not needed to run the tool — do one of:
40
+
41
+ ```bash
42
+ # From the source tree — a normal (non-editable) install builds a wheel:
43
+ pip install . # NOT pip install -e .
44
+
45
+ # ...or upgrade pip first, and editable works too:
46
+ pip install --upgrade pip && pip install -e .
47
+ ```
48
+
49
+ For a **truly air-gapped host**, build the wheels on a connected machine and copy
50
+ them over — the target then needs no network:
51
+
52
+ ```bash
53
+ # On a connected machine, collect this package + its dependencies as wheels:
54
+ pip wheel . -w dist # → dist/*.whl (or: uv build, for just this package)
55
+
56
+ # Copy dist/ to the air-gapped host, then install offline:
57
+ pip install --no-index --find-links dist vmware-debug
58
+ ```
59
+
60
+ ## License
61
+
62
+ MIT.
@@ -1,3 +1,34 @@
1
+ ## v1.8.7 (2026-07-21) — the skill-level read-only switch is removed; read/write authorization is the vCenter account's job (RBAC)
2
+
3
+ ### Removed: `VMWARE_READ_ONLY` / `read_only:` — give the agent a read-only service account instead
4
+
5
+ The skill-level read-only switch is gone. It was enforced only on the MCP tool
6
+ registry, and any agent with a shell (every SKILL.md grants `allowed-tools: Bash`)
7
+ could reach the same change one CLI command away — so it withheld the *tool*, not
8
+ the *capability*. It was never a real boundary.
9
+
10
+ To run an agent read-only, give it a **read-only vCenter/NSX service account
11
+ (RBAC)**. Writes are then refused at the platform, un-bypassably, regardless of
12
+ surface or shell — the one place read/write control cannot be stepped around. A
13
+ config still carrying `read_only: true` is ignored, with a one-time warning that
14
+ names the replacement (no silent behavior change).
15
+
16
+ ### Removed: approval tiers and the declared-environment gate (via vmware-policy)
17
+
18
+ The graduated-autonomy approval tiers (`confirm`/`dual`/`review`) and the "declare
19
+ an environment or be refused" baseline are removed — they only ever fired on the
20
+ rarest configuration while carrying the family's most complex machinery. Opt-in
21
+ `deny` rules and the maintenance window remain, and apply identically wherever a
22
+ tool runs.
23
+
24
+ ### Added: offline / air-gapped install docs
25
+
26
+ The README now covers installing from source without editable mode (for older
27
+ `pip`) and building wheels to carry onto an air-gapped host — the modern PEP 517
28
+ layout has no `setup.py` by design, which is expected, not a missing file.
29
+
30
+ This release also carries the accumulated fixes staged since 1.8.5.
31
+
1
32
  ## v1.8.5 (2026-07-20) — the two fixes v1.8.4 announced now actually work
2
33
 
3
34
  Four adversarial reviews of v1.8.4 found that both of its headline fixes were
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "vmware-debug"
7
- version = "1.8.5"
7
+ version = "1.8.7"
8
8
  description = "VMware diagnostic brain — read-only incident triage, log/event correlation, and root-cause routing across the VMware skill family"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -7,12 +7,12 @@
7
7
  "url": "https://github.com/zw008/VMware-Debug",
8
8
  "source": "github"
9
9
  },
10
- "version": "1.8.5",
10
+ "version": "1.8.7",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "pypi",
14
14
  "identifier": "vmware-debug",
15
- "version": "1.8.5",
15
+ "version": "1.8.7",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  }
@@ -19,7 +19,7 @@ installer:
19
19
  package: vmware-debug
20
20
  allowed-tools:
21
21
  - Bash
22
- metadata: {"openclaw":{"requires":{"bins":["vmware-debug"]},"optional":{"env":["VMWARE_READ_ONLY","VMWARE_DEBUG_READ_ONLY","VMWARE_AUDIT_APPROVED_BY","VMWARE_AUDIT_RATIONALE"],"bins":["vmware-policy"]},"primaryEnv":"NONE","homepage":"https://github.com/zw008/VMware-Debug","os":["macos","linux"]}}
22
+ metadata: {"openclaw":{"requires":{"bins":["vmware-debug"]},"optional":{"env":["VMWARE_AUDIT_APPROVED_BY","VMWARE_AUDIT_RATIONALE"],"bins":["vmware-policy"]},"primaryEnv":"NONE","homepage":"https://github.com/zw008/VMware-Debug","os":["macos","linux"]}}
23
23
  ---
24
24
 
25
25
  # VMware Debug
@@ -113,17 +113,11 @@ a recommended plan.
113
113
  See `references/event-envelope.md`. The agent normalises each source's events into this
114
114
  shape; debug stays source-agnostic and has no dependency on the other packages.
115
115
 
116
- ## Read-Only Mode
117
-
118
- Both tools here are reads, so read-only mode withholds nothing — but
119
- `VMWARE_DEBUG_READ_ONLY=true` or the family-wide `VMWARE_READ_ONLY=true` still applies, and
120
- the gate verifies at start-up that zero write tools are exposed rather than taking this
121
- document's word for it. Debug has no config file, so the env vars are the only switch. The
122
- same family variable withholds write tools across every companion skill, so a whole-estate
123
- audit posture is one setting — and when you route a fix to vmware-aiops or vmware-pilot and
124
- the tool is missing from *their* `list_tools()`, that is the lockdown, not a fault. Do not
125
- retry or hunt for another route: name the blocked operation and say an operator must clear
126
- the switch and restart that server. Running with local or small models? See [`references/agent-guardrails.md`](references/agent-guardrails.md).
116
+ ## Read-Only by Design
117
+
118
+ Both tools here are reads — zero write tools, zero network access of its own.
119
+ Running with local or small models? See
120
+ [`references/agent-guardrails.md`](references/agent-guardrails.md).
127
121
 
128
122
  ## CLI Quick Reference
129
123
 
@@ -34,50 +34,13 @@ These are structural, so it cannot.
34
34
 
35
35
  | Guardrail you would otherwise prompt for | Now enforced by |
36
36
  |---|---|
37
- | "Work exclusively in read-only mode and never modify anything" | **The tool surface, and the gate that proves it.** Both tools are reads, so read-only mode withholds nothing here — but setting it makes the guarantee checkable: the gate verifies at start-up that zero write tools are exposed rather than taking this document's word for it. |
37
+ | "Work read-only and never modify anything" | **The tool surface itself.** Both tools are reads — this skill has no write tool at all, so there is nothing to withhold and nothing to switch off. |
38
38
  | "Diagnose only — never apply the fix you propose" | **Structural.** This skill has no tool that changes anything, and it holds no connection to vCenter, NSX or anything else. Remediation is routed to vmware-aiops or vmware-pilot by the calling agent. |
39
39
  | "Do not fabricate a timeline — build it from the events I gave you" | **`incident_timeline` correlates only its input.** It is source-agnostic and has no way to fetch anything, so the timeline cannot contain an event the agent did not supply. |
40
40
  | "Tell me when the symptom is outside what you can recognise" | **`list_symptom_categories`** states the catalogue, and unmatched symptoms come back as `uncategorized` rather than being forced into the nearest signature. |
41
41
  | "Use explicit limits for queries that may return large amounts of data" | **The list envelope.** `list_symptom_categories` returns `{items, returned, limit, total, truncated, hint}` with `truncated` always `false` — which is the point: it states that the catalogue is complete instead of leaving you to infer it. |
42
42
  | "Log everything you looked at" | **The `@vmware_tool` decorator.** Every call is recorded to `~/.vmware/audit.db`, reads included. |
43
43
 
44
- ### Turning read-only mode on
45
-
46
- One variable covers every skill in the family:
47
-
48
- ```json
49
- {
50
- "mcpServers": {
51
- "vmware-debug": {
52
- "command": "vmware-debug",
53
- "args": ["mcp"],
54
- "env": { "VMWARE_READ_ONLY": "true" }
55
- }
56
- }
57
- }
58
- ```
59
-
60
- Per-skill override:
61
-
62
- ```bash
63
- VMWARE_READ_ONLY=true # whole family read-only
64
- VMWARE_DEBUG_READ_ONLY=false # …except this skill
65
- ```
66
-
67
- **This skill has no `config.yaml`**, so the two environment variables are the
68
- only switch — there is no `read_only:` configuration setting to fall back on.
69
- Precedence is per-skill env → family env → off. An unparseable value
70
- (`VMWARE_READ_ONLY=ture`) enables read-only mode rather than silently ignoring
71
- the typo.
72
-
73
- Setting it here is worth doing even though nothing is withheld: the same
74
- variable withholds write tools across every companion skill, so a whole-estate
75
- diagnostic posture is one setting. That matters especially in this skill's
76
- workflow — you gather signals read-only, correlate, and then route a fix. When
77
- the fix tool is missing from vmware-aiops's or vmware-pilot's `list_tools()`,
78
- that is the lockdown working, not a fault: name the blocked operation and stop,
79
- rather than retrying or hunting for another route.
80
-
81
44
  ---
82
45
 
83
46
  ## The system prompt
@@ -7,11 +7,6 @@ Read-only, offline incident correlation. No network, no credentials, no writes.
7
7
  | `incident_timeline` | `{event_count, window, spikes:[{start,end,count,zscore}], hypotheses:[{category, score, summary, evidence_count, first_seen, last_seen, sample_text, suggested_check}], next_checks:[...]}` | 300–2000 (scales with hypotheses) |
8
8
  | `list_symptom_categories` | `{items: [{category, example_keywords, suggested_check}], returned, limit, total, truncated, hint}` | ~400 |
9
9
 
10
- > Read-only mode (`VMWARE_DEBUG_READ_ONLY=true` or the family-wide `VMWARE_READ_ONLY=true`;
11
- > debug has no config file) removes nothing from this table — both tools are `[READ]`, and
12
- > the gate proves that at start-up rather than trusting the marker. Classification comes
13
- > from the `[READ]`/`[WRITE]` docstring marker — see README.
14
-
15
10
  `list_symptom_categories` returns the family list envelope — read the rows from
16
11
  `items`. It has no `limit` parameter, which is exactly why the envelope matters:
17
12
  `truncated: false` states that this is every category there is, rather than
@@ -0,0 +1,49 @@
1
+ # vmware-debug Setup Guide
2
+
3
+ vmware-debug has **no configuration, no credentials, and no network access** — it
4
+ is a pure, offline correlation engine. There is no `config.yaml` and no `.env`.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ uv tool install vmware-debug
10
+ vmware-debug categories # verify it runs
11
+ ```
12
+
13
+ ## MCP client configuration
14
+
15
+ ```json
16
+ {
17
+ "command": "uvx",
18
+ "args": ["--from", "vmware-debug", "vmware-debug-mcp"]
19
+ }
20
+ ```
21
+
22
+ If installed with `uv tool install`, prefer the entry point `vmware-debug mcp`
23
+ (no PyPI resolution at startup — robust behind corporate TLS proxies, 踩坑 #25).
24
+
25
+ For full cross-skill diagnosis, also install the data-source skills it correlates
26
+ (vmware-monitor, vmware-log-insight, vmware-aria, vmware-nsx) and the executors it
27
+ routes fixes to (vmware-aiops, vmware-pilot).
28
+
29
+ ## Security
30
+
31
+ > **Disclaimer**: Community-maintained open-source project, **not affiliated with,
32
+ > endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.**
33
+
34
+ 1. **Source Code** — https://github.com/zw008/VMware-Debug (MIT).
35
+ 2. **Credentials** — none. debug holds no secrets and connects to nothing.
36
+ 3. **Network** — none. All tools are local pure functions over event data the
37
+ agent supplies.
38
+ 4. **Writes** — none. debug only diagnoses and recommends; remediation is routed
39
+ to vmware-aiops / vmware-pilot, where confirmation/approval/audit live.
40
+ 5. **No cross-skill coupling** — events arrive as plain dicts (the event
41
+ envelope); debug imports no other skill package at runtime.
42
+ 6. **Environment scoping** — policy rules can scope by environment, and skills
43
+ that connect to a VMware estate may declare `environment:` (`production` /
44
+ `staging` / `lab`) per target in their own `config.yaml` as an optional label
45
+ an environment-scoped `deny` rule can match on. debug has no config and no
46
+ connection to declare one about, so it reports a constant `local`. Since it
47
+ ships no operation above read risk, nothing here is gated either way.
48
+ 7. **Static analysis** — `uvx bandit -r vmware_debug/` (release bar:
49
+ 0 Medium+).
@@ -34,13 +34,13 @@
34
34
  },
35
35
  "maximum": 1,
36
36
  "pct": 100.0,
37
+ "stale": true,
37
38
  "unit": "required entity params",
38
39
  "value": 1
39
40
  },
40
41
  "entry_point_availability": {
41
42
  "detail": {
42
- "full_entry_points": 2,
43
- "read_only_entry_points": 2
43
+ "full_entry_points": 2
44
44
  },
45
45
  "maximum": 2,
46
46
  "pct": 100.0,
@@ -53,16 +53,16 @@
53
53
  "dead_end_count": 0,
54
54
  "dead_end_errors": [],
55
55
  "per_dimension_pct": {
56
- "names_artifact": 100.0,
56
+ "names_artifact": 87.5,
57
57
  "names_input": 100.0,
58
58
  "states_remedy": 100.0
59
59
  },
60
- "raise_sites": 7
60
+ "raise_sites": 8
61
61
  },
62
- "maximum": 21,
63
- "pct": 100.0,
62
+ "maximum": 24,
63
+ "pct": 95.8,
64
64
  "unit": "points",
65
- "value": 21
65
+ "value": 23
66
66
  },
67
67
  "manifest_context_headroom": {
68
68
  "detail": {
@@ -109,6 +109,7 @@
109
109
  },
110
110
  "maximum": 450,
111
111
  "pct": 0.0,
112
+ "stale": true,
112
113
  "unit": "tokens",
113
114
  "value": 0
114
115
  },
@@ -126,23 +127,20 @@
126
127
  "budget_chars": 500,
127
128
  "over_budget": [],
128
129
  "remedy_after_interpolation": [
129
- "envelope.py:135",
130
- "envelope.py:95",
131
- "envelope.py:160",
132
- "envelope.py:107",
133
- "envelope.py:200",
130
+ "envelope.py:126",
131
+ "envelope.py:138",
134
132
  "timeline.py:119"
135
133
  ]
136
134
  },
137
- "maximum": 7,
135
+ "maximum": 8,
138
136
  "pct": 100.0,
139
137
  "unit": "messages",
140
- "value": 7
138
+ "value": 8
141
139
  },
142
140
  "teaching_error_rate": {
143
141
  "detail": {},
144
- "maximum": 7,
145
- "pct": 100.0,
142
+ "maximum": 8,
143
+ "pct": 87.5,
146
144
  "unit": "messages",
147
145
  "value": 7
148
146
  },
@@ -11,7 +11,6 @@ from __future__ import annotations
11
11
 
12
12
  import asyncio
13
13
  import importlib
14
- import os
15
14
  import sys
16
15
  from typing import Any
17
16
 
@@ -20,36 +19,26 @@ import pytest
20
19
  from ._scoring import ScoreBoard
21
20
  from ._skill import SERVER_MODULE, get_server
22
21
 
23
- #: Prefix of the modules the read-only gate affects at import time.
22
+ #: Prefix of the server modules re-imported by ``load_tools``.
24
23
  _SERVER_PREFIX = SERVER_MODULE.split(".")[0] + ".mcp_server"
25
24
 
26
- _READ_ONLY_ENV = "VMWARE_READ_ONLY"
27
-
28
25
 
29
26
  def load_tools(read_only: bool = False) -> tuple[Any, ...]:
30
27
  """Import the MCP server fresh and return the tools it registers.
31
28
 
32
- Re-imports rather than reusing the loaded module because the read-only gate
33
- runs at import time. The original module objects are restored afterwards —
34
- deleting them would leave other test files monkeypatching a module nobody
35
- imports any more, and their patches would silently stop applying.
29
+ Re-imports rather than reusing the loaded module because the tools register
30
+ themselves onto the registry at import time. The original module objects are
31
+ restored afterwards — deleting them would leave other test files
32
+ monkeypatching a module nobody imports any more, and their patches would
33
+ silently stop applying.
36
34
  """
37
35
  saved = {n: m for n, m in sys.modules.items() if n.startswith(_SERVER_PREFIX)}
38
- prior = os.environ.get(_READ_ONLY_ENV)
39
36
  try:
40
- if read_only:
41
- os.environ[_READ_ONLY_ENV] = "true"
42
- else:
43
- os.environ.pop(_READ_ONLY_ENV, None)
44
37
  for name in list(saved):
45
38
  del sys.modules[name]
46
39
  mod = importlib.import_module(SERVER_MODULE)
47
40
  return tuple(asyncio.run(get_server(mod).list_tools()))
48
41
  finally:
49
- if prior is None:
50
- os.environ.pop(_READ_ONLY_ENV, None)
51
- else:
52
- os.environ[_READ_ONLY_ENV] = prior
53
42
  for name in [n for n in sys.modules if n.startswith(_SERVER_PREFIX)]:
54
43
  del sys.modules[name]
55
44
  sys.modules.update(saved)
@@ -72,9 +61,3 @@ def tools() -> tuple[Any, ...]:
72
61
  model's context, not the docstring as written.
73
62
  """
74
63
  return load_tools(read_only=False)
75
-
76
-
77
- @pytest.fixture(scope="session")
78
- def gated_tools() -> tuple[Any, ...]:
79
- """The surface an operator gets under ``VMWARE_READ_ONLY=true``."""
80
- return load_tools(read_only=True)
@@ -9,9 +9,6 @@ another tool on the same surface, or from a description that names the specific
9
9
  producer to call. A parameter with neither is a **broken chain**: a tool the
10
10
  model can see, wants to use, and cannot correctly invoke.
11
11
 
12
- It scores the full surface and the ``VMWARE_READ_ONLY=true`` surface separately,
13
- because gating removes tools and can turn a working chain into a broken one.
14
-
15
12
  Why it matters for a small model
16
13
  --------------------------------
17
14
  This is the failure the whole family's structured-output work was aimed at,
@@ -47,10 +44,6 @@ route. **100%** every demanded name is obtainable; **80–99%** a few tools invi
47
44
  a guess; **<80%** identifier hallucination should be expected in normal use. The
48
45
  ``broken_chains`` detail lists the exact parameters to fix, and the cheapest fix
49
46
  is almost always one sentence in a description rather than a new tool.
50
-
51
- Compare the two scores against each other: a large drop under read-only mode
52
- means the safety gate is buying its safety by making the surface unusable, which
53
- is worth knowing before recommending it as a default.
54
47
  """
55
48
 
56
49
  from __future__ import annotations
@@ -323,47 +316,24 @@ def test_entity_reachability_full_surface(board, tools):
323
316
  )
324
317
 
325
318
 
326
- def test_entity_reachability_read_only_surface(board, gated_tools):
327
- """The same question after the read-only gate has removed tools.
328
-
329
- Recorded separately because a safety control that leaves the remaining tools
330
- uncallable has traded one failure mode for a worse one.
331
- """
332
- score = _record(board, gated_tools, "read_only")
333
- if not _assert_vocabulary_fits(score):
334
- return
335
- assert score.pct >= 50.0, (
336
- f"read-only mode drops entity reachability to {score.pct}% — the gate is "
337
- "making the surface unusable rather than merely safe"
338
- )
339
-
340
-
341
- def test_every_surface_has_an_entry_point(board, tools, gated_tools):
342
- """At least one tool must be callable with nothing in hand, in both modes.
319
+ def test_every_surface_has_an_entry_point(board, tools):
320
+ """At least one tool must be callable with nothing in hand.
343
321
 
344
322
  The degenerate broken surface: if every tool demands a name, there is no
345
323
  first call to make and the skill is unreachable regardless of model size.
346
324
  """
347
325
  full_entries = _entry_points(tools)
348
- gated_entries = _entry_points(gated_tools)
349
326
  board.add(
350
327
  Score(
351
328
  name="entry_point_availability",
352
- value=min(len(full_entries), len(gated_entries)),
353
- maximum=max(1, len(gated_tools)),
329
+ value=len(full_entries),
330
+ maximum=max(1, len(tools)),
354
331
  unit="entry points",
355
- detail={
356
- "full_entry_points": len(full_entries),
357
- "read_only_entry_points": len(gated_entries),
358
- },
332
+ detail={"full_entry_points": len(full_entries)},
359
333
  )
360
334
  )
361
- print(
362
- f"\n[capability] entry points: {len(full_entries)} full / "
363
- f"{len(gated_entries)} read-only"
364
- )
335
+ print(f"\n[capability] entry points: {len(full_entries)} full")
365
336
  assert full_entries, "no tool can be called without an entity name already in hand"
366
- assert gated_entries, "read-only mode left no callable entry point"
367
337
 
368
338
 
369
339
  def test_entity_vocabulary_covers_the_surface(tools):