{"id":"749e1127-1e58-4339-a90f-86cee3184ff2","entityType":"agent","slug":"clawhub-zw008-vmware-storage","name":"vmware-storage","canonicalUrl":"https://www.xpersona.co/agent/clawhub-zw008-vmware-storage","canonicalPath":"/agent/clawhub-zw008-vmware-storage","generatedAt":"2026-10-09T12:27:01.492Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:07:22.221Z","emptyReason":null},"description":"Use this skill whenever the user needs to manage VMware storage — datastores, iSCSI targets, and vSAN clusters. Directly handles: browse datastores, scan for deployable images (OVA/ISO), configure iSCSI adapters and targets, check vSAN health and capacity, read-only Fibre Channel HBA/WWPN inventory and multipath path state. Always use this skill for \"list datastores\", \"add iSCSI target\", \"check vSAN health\", \"browse datastore files\", \"scan for OVA images\", \"dead paths\", \"FC HBA WWPN\", or any storage-related VMware task. Do NOT use for VM lifecycle operations (use vmware-aiops), NSX networking (use vmware-nsx), or Kubernetes clusters (use vmware-vks). For load balancing/AVI/AKO use vmware-avi.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 5.3K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:vmware-storage","sourceUrl":"https://clawhub.ai/zw008/vmware-storage","homepage":"https://clawhub.ai/zw008/skills/vmware-storage","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/zw008/vmware-storage","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/zw008/skills/vmware-storage","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":50,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"vmware-storage technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:07:22.221Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:07:22.221Z","emptyReason":null},"stars":null,"forks":null,"downloads":5326,"packageName":null,"latestVersion":"1.12.0","tractionLabel":"5.3K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:07:22.221Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T04:07:22.221Z","lastCrawledAt":"2026-10-09T04:07:22.221Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T04:07:22.221Z","lastVerifiedAt":null,"highlights":[{"version":"1.12.0","createdAt":"2026-09-20T14:52:48.885Z","changelog":"MCP instructions now name the configured targets and how to choose one; a config that cannot be read says so instead of falling silent.","fileCount":8,"zipByteSize":27821},{"version":"1.11.0","createdAt":"2026-09-19T03:55:57.912Z","changelog":"Destructive MCP tools preview by default (confirm=False) and state their blast radius; confirm=True refuses on blockers or unreadable measurements. Requires vmware-policy>=1.17.0.","fileCount":8,"zipByteSize":27945},{"version":"1.10.0","createdAt":"2026-09-18T14:43:19.967Z","changelog":"Read-only Fibre Channel HBA inventory (WWPN/WWNN) and SCSI multipath diagnostics: fc_adapter_list, storage_device_paths. 12 -> 14 tools.","fileCount":8,"zipByteSize":27383},{"version":"1.9.3","createdAt":"2026-09-16T05:19:17.135Z","changelog":"A stopped MCP server exits within five seconds even if its logout hangs","fileCount":8,"zipByteSize":24126},{"version":"1.9.2","createdAt":"2026-09-15T14:39:41.273Z","changelog":"Stopping the MCP server now logs out its vCenter session.","fileCount":8,"zipByteSize":24010},{"version":"1.9.1","createdAt":"2026-09-15T06:07:31.301Z","changelog":"CLI reads are audited under their MCP tool names; every CLI command declares what it reaches (needs vmware-policy 1.15.0)","fileCount":8,"zipByteSize":24015},{"version":"1.9.0","createdAt":"2026-09-12T00:16:17.190Z","changelog":"CLI writes are authorised and audited under their MCP tool names, and environment-scoped deny rules now apply to CLI writes as well as MCP tools.","fileCount":8,"zipByteSize":24112},{"version":"1.8.17","createdAt":"2026-09-05T01:06:21.883Z","changelog":"a dropped connection no longer keeps itself alive","fileCount":8,"zipByteSize":24174}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:vmware-storage","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:vmware-storage` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/zw008/vmware-storage before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T12:27:01.486Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-vmware-storage/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:07:22.221Z","emptyReason":null},"readme":"Skill: vmware-storage\n\nOwner: zw008\n\nSummary: Use this skill whenever the user needs to manage VMware storage — datastores, iSCSI targets, and vSAN clusters. Directly handles: browse datastores, scan for deployable images (OVA/ISO), configure iSCSI adapters and targets, check vSAN health and capacity, read-only Fibre Channel HBA/WWPN inventory and multipath path state. Always use this skill for \"list datastores\", \"add iSCSI target\", \"check vSAN health\", \"browse datastore files\", \"scan for OVA images\", \"dead paths\", \"FC HBA WWPN\", or any storage-related VMware task. Do NOT use for VM lifecycle operations (use vmware-aiops), NSX networking (use vmware-nsx), or Kubernetes clusters (use vmware-vks). For load balancing/AVI/AKO use vmware-avi.\n\nTags: latest:1.12.0\n\nVersion history:\n\nv1.12.0 | 2026-09-20T14:52:48.885Z | user\n\nMCP instructions now name the configured targets and how to choose one; a config that cannot be read says so instead of falling silent.\n\nv1.11.0 | 2026-09-19T03:55:57.912Z | user\n\nDestructive MCP tools preview by default (confirm=False) and state their blast radius; confirm=True refuses on blockers or unreadable measurements. Requires vmware-policy>=1.17.0.\n\nv1.10.0 | 2026-09-18T14:43:19.967Z | user\n\nRead-only Fibre Channel HBA inventory (WWPN/WWNN) and SCSI multipath diagnostics: fc_adapter_list, storage_device_paths. 12 -> 14 tools.\n\nv1.9.3 | 2026-09-16T05:19:17.135Z | user\n\nA stopped MCP server exits within five seconds even if its logout hangs\n\nv1.9.2 | 2026-09-15T14:39:41.273Z | user\n\nStopping the MCP server now logs out its vCenter session.\n\nv1.9.1 | 2026-09-15T06:07:31.301Z | user\n\nCLI reads are audited under their MCP tool names; every CLI command declares what it reaches (needs vmware-policy 1.15.0)\n\nv1.9.0 | 2026-09-12T00:16:17.190Z | user\n\nCLI writes are authorised and audited under their MCP tool names, and environment-scoped deny rules now apply to CLI writes as well as MCP tools.\n\nv1.8.17 | 2026-09-05T01:06:21.883Z | user\n\na dropped connection no longer keeps itself alive\n\nv1.8.16 | 2026-08-31T07:25:01.426Z | user\n\none answer per .env, on every platform\n\nv1.8.15 | 2026-08-31T00:33:49.346Z | user\n\nfix: run the suite on a non-UTF-8 machine, and stop one skill answering for another\n\nv1.8.14 | 2026-08-30T15:18:09.832Z | user\n\nSecond-round fixes from the 2026-08-30 VCF 9.1 re-test; vmware-policy floor raised to 1.11.0 (the engine no longer fails open when rules.yaml cannot be read).\n\nv1.8.13 | 2026-08-30T09:34:13.339Z | user\n\nParameter descriptions now reach the MCP JSON schema (0% -> 100% coverage); additionalProperties closed; vmware-policy floor raised to 1.10.0.\n\nv1.8.12 | 2026-08-30T07:44:06.133Z | user\n\nvSAN health and capacity no longer answer for hosts and datastores they never reached; iSCSI status raises a teaching error instead of crashing on an unreachable host; doctor authenticates every target and reads the config the tools read.\n\nv1.8.11 | 2026-08-28T02:56:58.993Z | user\n\nFixes the server's self-reported version and the advertised tool count; adds a Claude Code plugin manifest.\n\nv1.8.10 | 2026-08-06T09:44:09.848Z | user\n\nvSAN data-efficiency read (vsan_efficiency, 11→12) + verify_ssl SSL-context fix for self-signed vSAN. + review hardening. global-dedup/v2v-replication intentionally not built (no SDK).\n\nv1.8.9 | 2026-08-01T03:12:37.884Z | user\n\nMoved to vmware-skills GitHub org; MCP Registry namespace → io.github.vmware-skills. Links updated.\n\nv1.8.8 | 2026-07-21T15:43:00.821Z | user\n\nCLI writes now route through the shared guard()+audit_call() core via @guarded, exactly like the MCP tools (HLD I-1/I-8). Requires vmware-policy>=1.8.8.\n\nv1.8.7 | 2026-07-21T11:39:06.547Z | user\n\nRemove read-only switch and approval tiers; read/write authz delegated to RBAC. Plus accumulated fixes since 1.8.5.\n\nv1.8.5 | 2026-07-20T13:03:28.914Z | user\n\nA failure that is returned is now audited as a failure, and certificate/URL detail no longer reaches the agent. Both fixes v1.8.4 announced were incomplete.\n\nv1.8.4 | 2026-07-20T08:25:10.846Z | user\n\nTeaching error messages, domain exceptions no longer redacted on the way to the agent, and tool descriptions that state when to use each tool and what to call next.\n\nv1.8.3 | 2026-07-20T03:42:54.388Z | user\n\nPer-target username can now come from an env var, resolved per access like the password; documented credential variables corrected against what each repo's code actually reads\n\nv1.8.2 | 2026-07-19T18:01:11.784Z | user\n\nMCP server moved into the package namespace — fixes two skills in one environment silently overwriting each other's server; agent-guardrails.md for local/small models now ships in every skill\n\nv1.8.1 | 2026-07-19T11:23:36.292Z | user\n\nRead-only mode now documented on every surface that teaches it (SKILL.md, setup-guide, capabilities) and reported by doctor\n\nv1.8.0 | 2026-07-19T09:41:26.872Z | user\n\nRead-only mode (4 write tools withheld), list-result envelope, declared environments\n\nv1.7.7 | 2026-07-17T06:56:27.937Z | user\n\nSession-probe eviction fix (dead cached sessions were never evicted; None currentSession now treated as dead) + lockfile mcp 1.28.1 clearing three GHSA HIGH advisories.\n\nv1.7.5 | 2026-07-13T07:17:19.877Z | user\n\nfamily version alignment (no code change)\n\nv1.7.4 | 2026-07-13T04:52:07.627Z | user\n\nFamily version alignment to 1.7.4 (substantive change this cycle is in vmware-monitor: host-check boundary read batching).\n\nv1.7.3 | 2026-07-03T00:48:31.488Z | user\n\nFamily version alignment (v1.7.3)\n\nv1.7.2 | 2026-07-02T14:31:00.129Z | user\n\nBatch datastore/host inventory via PropertyCollector (issue #31 port)\n\nv1.7.1 | 2026-07-02T10:53:10.247Z | user\n\nFamily version alignment with v1.7.1 (AIops/Monitor large-inventory scale fix, issue #31).\n\nv1.7.0 | 2026-06-27T01:01:17.518Z | user\n\nguided init wizard + auth/TLS error teaching\n\nv1.6.1 | 2026-06-24T00:00:48.050Z | user\n\nv1.6.1 .env password b64 obfuscation\n\nv1.6.0 | 2026-06-22T09:17:10.681Z | user\n\nv1.6.0 trust architecture: undo tokens + governance harness (budget/audit/risk-tiers)\n\nv1.5.39 | 2026-06-22T00:42:05.900Z | user\n\nv1.5.39: AIops snapshot-delete async + honest timeout (token-burn fix), Storage browse timeout fix; others version-aligned\n\nv1.5.38 | 2026-06-12T06:59:57.900Z | user\n\nrelease alignment\n\nv1.5.37 | 2026-06-12T01:58:41.202Z | user\n\nbacklog: faster datastore listing, iSCSI race, ops tests\n\nv1.5.36 | 2026-06-11T23:22:10.628Z | user\n\nOVA scanning fix + destructive-op gating\n\nv1.5.35 | 2026-06-10T00:45:21.117Z | user\n\nSecurity hardening: safe error handling, TLS/path/permission fixes\n\nv1.5.32 | 2026-06-08T02:47:19.294Z | user\n\nv1.5.32: audit-clean confirmation + hardened test suite\n\nv1.5.30 | 2026-06-07T13:22:58.790Z | user\n\nv1.5.30: Glama TDQS tool description quality rewrite\n\nv1.5.29 | 2026-05-29T02:20:00.580Z | user\n\npatterns/iscsi-target-stale-rescan.yaml L5 PoC documented; Python 3.10 support\n\nv1.5.28 | 2026-05-20T10:00:08.096Z | user\n\nFix subclass() arg 1 must be a class in goose/old-mcp environments. v1.5.25-1.5.27 only addressed PEP 604 X|None -> Optional[X] but kept 'from __future__ import annotations'; under mcp 1.10-1.13 FastMCP's issubclass() on string annotations crashed server load. This release removes the future import. CLAUDE.md pitfall #33 updated.\n\nv1.5.27 | 2026-05-20T06:57:22.108Z | user\n\nLoosen Python requirement to >= 3.10 (was >=3.11). v1.5.25/26 PEP 604 fix already enables 3.10 at runtime; this release lifts pip download/install block.\n\nv1.5.26 | 2026-05-20T06:17:30.485Z | user\n\nMCP server Python 3.10 compatibility (踩坑 #33): PEP 604 X|None → Optional[X] in tool signatures; mcp_cmd Python version guard; mcp[cli]>=1.10\n\nv1.5.23 | 2026-05-19T02:59:01.248Z | user\n\nVCF 9.0 / 9.1 compatibility declared. README version-compat tables updated. Added Official Broadcom References (VCF Python SDK, REST APIs, CLI tools).\n\nv1.5.22 | 2026-05-08T23:25:04.215Z | user\n\nv1.5.22 family alignment for Smithery rollout\n\nv1.5.21 | 2026-05-08T23:20:30.479Z | user\n\nv1.5.21 family alignment + python-multipart 0.0.27\n\nv1.5.20 | 2026-05-08T22:39:50.543Z | user\n\nv1.5.20 family alignment + MCP Registry mcp-name markers\n\nv1.5.19 | 2026-05-06T04:03:54.304Z | user\n\nv1.5.19 — yjs review fixes: NSX CLI subcommand imports (CRITICAL), VKS delete_tkc_cluster ApiClient leak, Harden Twin snapshot_id indexes + LEFT JOIN report, Policy approval gate + singleton lock; py3.11+ requirement; family_smoke recursive subcommand smoke.\n\nv1.5.18 | 2026-05-02T12:11:44.253Z | user\n\nv1.5.18 — family alignment + tooling normalization. Migrated dev deps to [dependency-groups] (PEP 735); added regression eval suite (tests/eval/regression/) catching v1.5.x release blockers.\n\nArchive index:\n\nArchive v1.12.0: 8 files, 27821 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (8820b), references/capabilities.md (12615b), references/cli-reference.md (8998b), references/setup-guide.md (10641b), skill-card.md (2531b), SKILL.md (20249b), _meta.json (134b)\n\nFile v1.12.0:SKILL.md\n\n---\nname: vmware-storage\ndescription: >\n  Use this skill whenever the user needs to manage VMware storage — datastores, iSCSI targets, and vSAN clusters.\n  Directly handles: browse datastores, scan for deployable images (OVA/ISO), configure iSCSI adapters and targets, check vSAN health and capacity, read-only Fibre Channel HBA/WWPN inventory and multipath path state.\n  Always use this skill for \"list datastores\", \"add iSCSI target\", \"check vSAN health\", \"browse datastore files\", \"scan for OVA images\", \"dead paths\", \"FC HBA WWPN\", or any storage-related VMware task.\n  Do NOT use for VM lifecycle operations (use vmware-aiops), NSX networking (use vmware-nsx), or Kubernetes clusters (use vmware-vks).\n  For load balancing/AVI/AKO use vmware-avi.\ninstaller:\n  kind: uv\n  package: vmware-storage\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"vmware-storage\",\"uvx\"]},\"optional\":{\"env\":[\"VMWARE_STORAGE_CONFIG\",\"VMWARE_<TARGET>_PASSWORD\",\"VMWARE_<TARGET>_USERNAME\",\"VMWARE_AUDIT_APPROVED_BY\"],\"bins\":[\"vmware-policy\"]},\"homepage\":\"https://github.com/vmware-skills/VMware-Storage\",\"emoji\":\"🗄️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  vmware-policy auto-installed as Python dependency (provides @vmware_tool decorator and audit logging). All write operations audited to ~/.vmware/audit.db.\n  Credentials: Each vCenter/ESXi target requires a per-target password env var in ~/.vmware-storage/.env following the pattern VMWARE_<TARGET_NAME_UPPER>_PASSWORD (e.g., target \"my-vcenter\" → VMWARE_MY_VCENTER_PASSWORD). No webhooks or outbound network calls — this skill is local-only (stdio MCP + vSphere API). Audit logs written to ~/.vmware/audit.db (SQLite WAL, local only).\n---\n\n# VMware Storage\n\n> **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom. Source code is publicly auditable at [github.com/vmware-skills/VMware-Storage](https://github.com/vmware-skills/VMware-Storage) under the MIT license.\n\nVMware vSphere storage management — 14 MCP tools for datastores, iSCSI, vSAN, and Fibre Channel / multipath diagnostics.\n\n> Split from vmware-aiops for lighter context and local model compatibility.\n> **Companion skills**: [vmware-aiops](https://github.com/vmware-skills/VMware-AIops) (VM lifecycle), [vmware-monitor](https://github.com/vmware-skills/VMware-Monitor) (read-only monitoring), [vmware-vks](https://github.com/vmware-skills/VMware-VKS) (Tanzu Kubernetes), [vmware-nsx](https://github.com/vmware-skills/VMware-NSX) (NSX networking), [vmware-nsx-security](https://github.com/vmware-skills/VMware-NSX-Security) (DFW/firewall), [vmware-aria](https://github.com/vmware-skills/VMware-Aria) (metrics/alerts/capacity), [vmware-avi](https://github.com/vmware-skills/VMware-AVI) (AVI/ALB/AKO), [vmware-harden](https://github.com/vmware-skills/VMware-Harden) (compliance baselines).\n> | [vmware-pilot](../vmware-pilot/SKILL.md) (workflow orchestration) | [vmware-policy](../vmware-policy/SKILL.md) (audit/policy)\n\n## What This Skill Does\n\n| Category | Tools | Count |\n|----------|-------|:-----:|\n| **Datastore** | list all datastores, browse files, scan for OVA/ISO/OVF/VMDK images, list cached images | 4 |\n| **iSCSI** | enable adapter, show status, add target, remove target, rescan HBAs | 5 |\n| **vSAN** | cluster health summary, capacity overview (total/used/free), data-efficiency (dedup/compression) | 3 |\n| **FC / multipath** (read-only) | FC HBA inventory with WWPN/WWNN; per-device path state across hosts, datastore backing devices, path-count differences across hosts | 2 |\n\n## Quick Install\n\n```bash\nuv tool install vmware-storage==1.12.0\nvmware-storage init      # guided setup: writes config + .env (chmod 600, password grep-safe), then verifies\nvmware-storage doctor\n```\n\n## When to Use This Skill\n\n- Browse datastore files or scan for deployable images (OVA/ISO/VMDK)\n- Configure iSCSI: enable adapter, add/remove send targets, rescan storage\n- Check vSAN cluster health and capacity\n- Fibre Channel: list HBAs and WWPNs, find dead/disabled paths, compare path counts across a cluster, map a datastore to its devices\n- Any storage-focused VMware operation\n\n**Use companion skills for**:\n- VM lifecycle, deployment, guest ops → `vmware-aiops`\n- Inventory, health, alarms, events → `vmware-monitor`\n- Tanzu Kubernetes → `vmware-vks`\n- Load balancing, AVI/ALB, AKO, Ingress → `vmware-avi`\n\n## Related Skills — Skill Routing\n\n| User Intent | Recommended Skill |\n|-------------|-------------------|\n| Read-only monitoring, alarms, events | **vmware-monitor** |\n| Storage: iSCSI, vSAN, datastores | **vmware-storage** ← this skill |\n| VM lifecycle, deployment, guest ops | **vmware-aiops** |\n| Tanzu Kubernetes (vSphere 8.x+) | **vmware-vks** |\n| NSX networking: segments, gateways, NAT | **vmware-nsx** |\n| NSX security: DFW rules, security groups | **vmware-nsx-security** |\n| Aria Ops: metrics, alerts, capacity planning | **vmware-aria** |\n| Multi-step workflows with approval | **vmware-pilot** |\n| Compliance baselines (CIS / 等保 / PCI-DSS), drift detection, LLM remediation advisor | **vmware-harden** (`uv tool install vmware-harden`) |\n| Load balancer, AVI, ALB, AKO, Ingress | **vmware-avi** (`uv tool install vmware-avi`) |\n| Audit log query | **vmware-policy** (`vmware-audit` CLI) |\n\n## Common Workflows\n\n### Set Up iSCSI Storage on a Host\n\n**Pre-flight (judgment)**:\n- Network reachability: `vmkping <iscsi-target-ip>` from the ESXi host must succeed BEFORE adding the target. Adding an unreachable target leaves the host in a degraded state, retrying forever.\n- Adapter sanity: `iscsi status` first — if already enabled, do not \"re-enable\"; just add the target.\n- Idempotency: `add-target` is idempotent (re-adding same IP is a no-op), but `remove-target` is not safely reversible mid-IO. Always verify no LUNs from this target are in use before removing.\n- Existing targets: list them first; some sites add targets one-per-host while others use cluster-wide. Check site convention.\n\n**Steps**:\n1. `iscsi status esxi-01` → confirm adapter state and existing targets\n2. `iscsi enable esxi-01 --dry-run` then real (skip if already enabled)\n3. `iscsi add-target esxi-01 <ip> --dry-run` then real (auto-rescans on success)\n4. `iscsi status esxi-01` again → confirm target listed AND devices appearing\n5. If devices missing 30+ sec after add: `iscsi rescan esxi-01` once more, then check ESXi-side `vmkping` and target ACL\n\n### Find Deployable Images Across Datastores\n\n**Judgment**: image search is read-only and safe, but blind scanning of every datastore is slow on large estates. Filter first.\n\n1. `datastore list` → get the inventory; ignore datastores marked `inaccessible` or low free space\n2. `datastore scan-images <ds>` on the datastore most likely to hold images (typically named `iso-*`, `templates`, or central `nfs-shared`)\n3. If unsure where images live: scan multiple in parallel via separate calls; results are cached in the local registry\n4. `datastore browse <ds> --pattern \"*.iso\"` for ad-hoc searches; pattern is glob, not regex\n5. **If datastore not found**: name is case-sensitive. `datastore list --target <vc>` to verify exact spelling.\n\nFor filtered queries against the cache: use `list_cached_images` MCP tool with `image_type` and `datastore` parameters — avoids re-scanning.\n\n### vSAN Health Assessment\n\n**Judgment**: vSAN problems often masquerade as vSphere problems and vice-versa. Check both planes — if vSAN is healthy but VMs are slow, the issue is at the compute or network layer, not storage.\n\n1. `vsan health <cluster>` → look beyond green/red — check disk group state, network partitioning, and cluster member counts. A \"yellow\" disk group is the early warning of a failure.\n2. `vsan capacity <cluster>` → utilization > 70% triggers slack-space risk; > 80% impedes resync; never let prod cross 80%.\n3. Cross-check `vmware-monitor health alarms` for vSAN-related alarms (HCL warnings, network anomalies)\n4. **If vSAN not enabled** on this cluster: check cluster type via `vmware-monitor inventory clusters`; vSAN is opt-in, not default\n5. For deep investigation, follow [`references/investigation-protocol.md`](../vmware-aria/skills/vmware-aria/references/investigation-protocol.md) (in companion skill) — vSAN issues frequently fail the Mechanism criterion (capacity is correlated, not causal)\n\n### Check Fibre Channel Paths\n\n**Judgment**: report what vSphere observed, not a verdict. `standby` paths are normal on active/passive arrays, and equal path counts do not prove two independent fabrics. Zoning, array masking and switch health are out of scope.\n\n1. `paths devices --datastore <ds>` → dead/disabled paths behind one datastore, per host (devices needing attention sort first)\n2. `paths devices --cluster <c> --only-differences` → shared devices some hosts do not see, or see through a different number of paths; each host's `paths_total` shows which has fewer\n3. `paths devices --host <h> --adapter vmhba2` → what depends on one HBA; `only_paths_via_adapter: true` means that host has no other path to the device\n4. `paths fc-adapters --cluster <c>` → WWPNs to hand to the SAN team\n5. **If `complete` is false**: hosts in `hosts_not_read` were not read (the reason says `NoPermission` or the connection state). Name them as unknown — never report them as missing the device\n6. **If \"Scope required\"**: pass exactly one of `--cluster`, `--host` or `--datastore`; this tool does not read every host at once\n\n### Multi-Target Operations\n\nAll commands accept `--target <name>` to operate against a specific vCenter or ESXi host from your config:\n\n```bash\n# Default target (first in config.yaml)\nvmware-storage datastore list\n\n# Specific target\nvmware-storage datastore list --target prod-vcenter\nvmware-storage iscsi status esxi-lab --target lab-esxi\n```\n\n## Usage Mode\n\n| Scenario | Recommended | Why |\n|----------|:-----------:|-----|\n| Local/small models (Ollama, Qwen) | **CLI** | ~2K tokens vs ~8K for MCP |\n| Cloud models (Claude, GPT-4o) | Either | MCP gives structured JSON I/O |\n| Automated pipelines | **MCP** | Type-safe parameters, structured output |\n\n## MCP Tools (14 — 10 read, 4 write)\n\nAll MCP tools accept an optional `target` parameter to select which vCenter/ESXi to connect to. The 4 write tools take `confirm` (default false): without it they change nothing and return `blast_radius` — the host and adapters touched, and for `storage_iscsi_remove_target` the paths, devices and datastores behind the target. Show it to the user; pass `confirm: true` only after they decide. `dry_run` is a deprecated alias.\n\nThe four Datastore read tools return the family list envelope — `{items, returned, limit, total, truncated, hint}` — rather than a bare array. Read the rows from `items`; `truncated` says whether the listing is complete, so it never has to be guessed from the row count. All four enumerate their collection in full, so `total` is the real count and `truncated` is always `false`.\n\n| Category | Tool | Type | Description |\n|----------|------|:----:|-------------|\n| Datastore | `list_all_datastores` | Read | List datastores with capacity, usage %, VM count |\n| | `browse_datastore` | Read | Browse files with optional path and glob pattern |\n| | `scan_datastore_images` | Read | Find OVA/ISO/OVF/VMDK in a datastore |\n| | `list_cached_images` | Read | Query local image registry with type/datastore filters |\n| iSCSI | `storage_iscsi_status` | Read | Show adapter status, HBA device, IQN, send targets |\n| | `storage_iscsi_enable` | Write | Enable software iSCSI adapter on a host |\n| | `storage_iscsi_add_target` | Write | Add iSCSI send target (IP + port) and rescan |\n| | `storage_iscsi_remove_target` | Write | Remove iSCSI send target and rescan |\n| | `storage_rescan` | Write | Rescan all HBAs and VMFS volumes |\n| vSAN | `vsan_health` | Read | Cluster health summary and disk group details |\n| | `vsan_capacity` | Read | Total/used/free capacity in GB and usage % |\n| | `vsan_efficiency` | Read | Dedup + compression status (vSAN Management SDK) |\n| FC / multipath | `fc_adapter_list` | Read | FC/FCoE HBAs per host: WWPN/WWNN, port type, status, reported speed |\n| | `storage_device_paths` | Read | Per-device path state across a cluster/host/datastore; visibility and path-count differences |\n\n**Read/write split**: 10 tools are read-only, 4 modify state. Write tools require explicit parameters (host name, IP address), preview unless `confirm: true`, refuse when a datastore would lose every path or the host's storage view cannot be read, and are audit-logged. `storage_iscsi_remove_target` is classified `risk:high` (destructive — LUNs can become inaccessible) and goes through the policy confirmation gate.\n\nRunning with local or small models? See [`references/agent-guardrails.md`](references/agent-guardrails.md).\n\n## CLI Quick Reference\n\n```bash\n# Datastore\nvmware-storage datastore list [--target <name>]\nvmware-storage datastore browse <ds_name> [--path <subdir>] [--pattern \"*.ova\"]\nvmware-storage datastore scan-images <ds_name> [--target <name>]\n\n# iSCSI\nvmware-storage iscsi enable <host> [--dry-run]\nvmware-storage iscsi status <host>\nvmware-storage iscsi add-target <host> <ip> [--port 3260] [--dry-run]\nvmware-storage iscsi remove-target <host> <ip> [--port 3260] [--dry-run]\nvmware-storage iscsi rescan <host> [--dry-run]\n\n# vSAN\nvmware-storage vsan health <cluster> [--target <name>]\nvmware-storage vsan capacity <cluster> [--target <name>]\n\n# Fibre Channel / multipath (read-only)\nvmware-storage paths fc-adapters [--cluster <c> | --host <h>]\nvmware-storage paths devices (--cluster <c> | --host <h> | --datastore <ds>) [--device <naa>] [--adapter <vmhba>] [--only-differences]\n\n# Diagnostics\nvmware-storage doctor [--skip-auth]\n```\n\n> Full CLI reference with all options and output formats: see `references/cli-reference.md`\n\n## Troubleshooting\n\n### iSCSI enable fails with \"already enabled\"\n\nNot an error. The software iSCSI adapter is already active on that host. The response includes the current HBA device name and IQN. Run `iscsi status` to see configured send targets.\n\n### \"Datastore not found\" when browsing\n\nDatastore names are **case-sensitive**. Run `vmware-storage datastore list` to get the exact name. Common mistakes: `Datastore1` vs `datastore1`, trailing spaces.\n\n### `vsan_health` returns `overall_health: null`\n\n`null` means the health service was **not asked**, and `health_not_queried_reason` says why. It is deliberately not the string `\"unknown\"` — vSAN returns that itself, so using it for \"we did not ask\" made the two impossible to tell apart (on one VCF 9.1 cluster it stood in for `red`). A string in `overall_health` is always vSAN's own answer.\n\nThe usual cause is a **standalone ESXi** target: `VsanVcClusterHealthSystem` runs in vCenter's vSAN Health Service, so connect to the vCenter that manages the cluster. Otherwise read it in the vCenter UI under Cluster > Monitor > vSAN > Skyline Health.\n\n`health_checked_at` is the age of vCenter's cached summary. This tool reads that cache — the same one Skyline Health shows — rather than triggering a full health run, which takes minutes and loads the cluster.\n\n### Rescan doesn't discover new LUNs\n\nAfter adding iSCSI targets, the storage subsystem may need 10-30 seconds to enumerate new LUNs. Steps to resolve:\n1. Verify the target IP is reachable from the ESXi host (`vmkping` from ESXi shell)\n2. Check that the iSCSI target is correctly configured: `vmware-storage iscsi status <host>`\n3. Wait 15-30 seconds, then rescan again: `vmware-storage iscsi rescan <host>`\n\n### \"Password not found\" error\n\nThe password environment variable is missing. Variable names follow the pattern `VMWARE_<TARGET_NAME_UPPER>_PASSWORD` where hyphens become underscores. Example: target `my-vcenter` needs `VMWARE_MY_VCENTER_PASSWORD`. Check your `~/.vmware-storage/.env` file.\n\n### Doctor reports \".env permissions too open\"\n\nThe `.env` file contains passwords and must have owner-only permissions:\n\n```bash\nchmod 600 ~/.vmware-storage/.env\n```\n\n### Connection timeout to vCenter\n\nThe `doctor` command tests connectivity with a 5-second TCP timeout. If your vCenter is on a high-latency network, the check may fail even though the connection works. Use `--skip-auth` to bypass both connectivity and auth checks, then test manually.\n\n### `invalid peer certificate: UnknownIssuer` when starting MCP via uvx\n\nCorporate TLS proxies inject certificates that uv's bundled CA store doesn't trust. Use the recommended `vmware-storage mcp` form (no PyPI re-resolve), or set `export UV_NATIVE_TLS=true` to make uv use system CAs.\n\n## Safety\n\n- **No VM operations**: This skill cannot power on/off, create, delete, or modify VMs — that scope belongs to `vmware-aiops`\n- **Read-heavy**: 10 of 14 tools are read-only (list, browse, scan, cached images, status, health, capacity, efficiency, FC adapters, device paths)\n- **Audit logging**: All operations (including reads) are logged to `~/.vmware/audit.db` (SQLite WAL, via vmware-policy) with timestamp, user, target, operation, parameters, and result\n- **Double confirmation**: CLI write commands (iSCSI enable, add/remove target) require two separate \"Are you sure?\" prompts before executing\n- **Dry-run mode**: All write commands support `--dry-run` to preview API calls without executing\n- **Input validation**: IP addresses validated via `ipaddress.ip_address()`, ports checked for 1-65535 range, host/cluster/datastore names looked up before operations\n- **Prompt injection defense**: Datastore file names and paths from vSphere are sanitized via `_sanitize()` — strips control characters (C0/C1), truncates to 500 chars — preventing malicious file names from injecting instructions into downstream LLM agents\n- **Credential safety**: Passwords loaded only from environment variables (`.env` file), never from `config.yaml`; `.env` permissions are checked at startup\n- **L5 auto-remediation patterns (PoC)**: The [`patterns/`](../../patterns/) directory hosts L5 auto-remediation **candidate** patterns under the Enterprise Harness Engineering framework. First PoC: [`patterns/iscsi-target-stale-rescan.yaml`](../../patterns/iscsi-target-stale-rescan.yaml) — iSCSI HBA rescan classified as `risk:low` + `reversible:true` + `repeatable:true`. Schema only; **not yet enforced by the runtime**. See `references/capabilities.md` § Automation Level Reference for the full L1–L5 table.\n\n> Full security details: see `references/setup-guide.md`\n\n## Setup\n\n```bash\nuv tool install vmware-storage==1.12.0\nmkdir -p ~/.vmware-storage\ncp config.example.yaml ~/.vmware-storage/config.yaml\n# Edit config.yaml with your vCenter/ESXi targets\n\n# Add to ~/.vmware-storage/.env (create if missing, chmod 600):\n# VMWARE_MY_VCENTER_PASSWORD=<your-password>\nchmod 600 ~/.vmware-storage/.env\n\nvmware-storage doctor\n```\n\n> All tools are automatically audited via vmware-policy. Audit logs: `vmware-audit log --last 20`\n\n> Full setup guide with multi-target config, MCP server setup, and Docker: see `references/setup-guide.md`\n\n## Architecture\n\n```\nUser (natural language)\n  ↓\nAI Agent (Claude Code / Goose / Cursor)\n  ↓ reads SKILL.md\nvmware-storage CLI or MCP server (stdio transport)\n  ↓ pyVmomi (vSphere SOAP API)\nvCenter Server / ESXi\n  ↓\nDatastores / iSCSI / vSAN\n```\n\nThe MCP server uses stdio transport (local only, no network listener). Connections to vSphere use SSL/TLS on port 443.\n\n## Audit & Safety\n\nAll operations are automatically audited via vmware-policy (`@vmware_tool` decorator):\n- Every tool call logged to `~/.vmware/audit.db` (SQLite, framework-agnostic)\n- Policy rules enforced via `~/.vmware/rules.yaml` (deny rules, maintenance windows, risk levels)\n- Risk classification: each tool tagged as low/medium/high/critical\n- View recent operations: `vmware-audit log --last 20`\n- View denied operations: `vmware-audit log --status denied`\n\nvmware-policy is automatically installed as a dependency — no manual setup needed.\n\n## License\n\nMIT — [github.com/vmware-skills/VMware-Storage](https://github.com/vmware-skills/VMware-Storage)\n\nFile v1.12.0:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"vmware-storage\",\n  \"version\": \"1.12.0\",\n  \"publishedAt\": 1789915968885\n}\n\nFile v1.12.0:references/agent-guardrails.md\n\n# Operating vmware-storage with a local / small model\n\nClaude-class models drive this skill without special instruction. Smaller and\nlocally-hosted models — Llama 3.3 70B, Qwen, Mistral, and similar, served\nthrough Goose, Ollama, or OpenShift AI — need explicit operating rules to call\ntools reliably.\n\nThis page exists because an operator wrote those rules by hand first. The\nguardrails below are adapted, with thanks, from the working configuration\n[@juanpf-ha](https://github.com/juanpf-ha) developed while running\nvmware-monitor and vmware-aria against a production vSphere estate with Llama\n3.3 70B FP8 on an on-prem H100\n([VMware-AIops#31](https://github.com/vmware-skills/VMware-AIops/issues/31)). The\ncross-skill rules are identical across this family; the parts below marked\nvmware-storage are specific to this skill.\n\nvmware-storage exposes 14 MCP tools, 4 of which change state. The write\nsurface is small but sharp: removing an iSCSI send target can make LUNs — and\nevery VM living on them — inaccessible.\n\n> **Disclaimer**: This is a community-maintained open-source project and is\n> **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom\n> Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom.\n\n---\n\n## First: the rules you no longer need to write\n\nSeveral guardrails from the original configuration are now enforced by the\nskill itself. Prompt instructions are advisory — a model can ignore them.\nThese are structural, so it cannot.\n\n| Guardrail you would otherwise prompt for | Now enforced by |\n|---|---|\n| \"Preview the change before applying it\" | **`confirm` defaults to false.** A call to any of the 4 write tools without `confirm: true` changes nothing and returns `blast_radius`. Previewing is the default path, not a convention the model has to remember to honour. |\n| \"Don't cut off storage that is in use\" | **Refusal.** `storage_iscsi_remove_target` with `confirm: true` is refused when a datastore would lose every path, or when any path or static target behind the send target cannot be attributed. |\n| \"Use explicit limits for queries that may return large amounts of data\" | **The list envelope.** The four datastore read tools return `{items, returned, limit, total, truncated, hint}`, so the model reads truncation instead of guessing at it. All four enumerate their collection in full, so `total` is the real count and `truncated` is always `false`. |\n| \"If a listing came back empty, say so rather than claiming the call failed\" | Same envelope. Empty `items` with `truncated: false` means checked-and-none — a stated result, not a silence the model has to interpret. |\n| \"Log every state change you make\" | **The `@vmware_tool` decorator.** Every operation is recorded to `~/.vmware/audit.db` before the model sees the result, and policy rules are evaluated ahead of execution. `storage_iscsi_remove_target` is classified `risk:high` and goes through the policy confirmation gate. |\n\n---\n\n## The system prompt\n\nEverything below still benefits from being stated explicitly. Copy this into\nyour agent's instruction block.\n\n```text\n## Tool use\n\n- Always call an MCP tool before answering any question about the current\n  VMware environment. Never answer from memory or assumption.\n- Never describe a tool call, and never output a JSON example, instead of\n  executing the tool. If you intend to call a tool, call it.\n- If a tool fails, report the actual error text. Do not complete the answer\n  with assumptions about what the result would have been.\n- Use explicit limits on queries that may return large amounts of data. Do not\n  request unlimited results unless the user asks for them.\n- Datastore and host names are case-sensitive. Resolve the exact name with a\n  list tool before using it; do not correct or reformat what the user typed.\n\n## Skill routing\n\n- vmware-storage: datastores, datastore browsing, image scanning, iSCSI\n  adapters and send targets, vSAN health and capacity, and read-only Fibre\n  Channel HBA inventory and multipath path state.\n- vmware-monitor: read-only vCenter inventory, hosts, alarms, events,\n  performance. Prefer it for any question that only reads.\n- vmware-aiops: VM lifecycle. This skill cannot power, create, delete or\n  reconfigure a VM — route those there.\n- vmware-vks: Supervisor storage policies and namespace storage usage.\n- vmware-aria: capacity forecasting and trend analysis.\n- vmware-pilot: multi-step workflows that need approval gates.\n\n## Data fidelity\n\n- Never invent datastores, hosts, LUNs, targets, or capacity figures. If a tool\n  did not return it, it does not exist for this answer.\n- Preserve the exact status, health-state and accessibility values the tools\n  return. Do not translate, normalise, or prettify enum values.\n- Report capacity in the units the tool returned. Do not convert GB to TB or\n  recompute a usage percentage yourself.\n- If a requested field was not returned, show it as \"not available\". Do not\n  infer it from other fields.\n- Preserve the original order and the full set of fields when the user asks\n  for specific ones.\n- When a response is long, report every item it contains. If a result is\n  truncated, the tool says so explicitly — report the truncation rather than\n  describing the visible subset as the whole.\n\n## Analysis discipline\n\n- Separate observed data from interpretation. State which is which.\n- Do not claim a capacity, performance, or configuration problem unless the\n  tool output contains explicit supporting evidence. A datastore at 80% is a\n  number, not an incident.\n- Avoid generic recommendations that are not directly supported by the results.\n\n## Writes in vmware-storage\n\n- Call any iSCSI or rescan tool without confirm first, show the user the\n  returned blast_radius, and pass confirm: true only after they decide.\n- storage_iscsi_remove_target is destructive: LUNs behind that target can become\n  inaccessible, taking their VMs with them. Say so before proposing it.\n- \"Already enabled\" from storage_iscsi_enable is not an error. Report the\n  returned HBA device and IQN.\n- After adding a target, the storage subsystem needs 10-30 seconds before new\n  LUNs appear. An empty rescan result is not proof the target is wrong.\n```\n\n---\n\n## Known failure modes on small models\n\nObserved with Llama 3.3 70B FP8 (Goose, on-prem H100), and useful as a\nchecklist when evaluating any local model against these skills:\n\n| Symptom | Mitigation |\n|---|---|\n| Describes a tool call, or emits a JSON example, instead of executing it | The \"never describe a tool call\" rule above. Also check your harness is not echoing tool schemas into context — models imitate the nearest format they see. |\n| Long tool responses: omits items, or reports \"no data returned\" when data was present | Ask for explicit limits so responses stay small. Check the envelope's `truncated` / `returned` / `total` fields rather than trusting the model's summary — a \"no data\" claim is checkable against `returned`. |\n| Adds generic recommendations unsupported by results | The \"analysis discipline\" rules. Capacity output invites invented advice more than most — hold it to the evidence. |\n| Drops requested fields or reorders results | State the required fields and ordering in the request itself, not only in the system prompt. |\n| Multi-tool workflows take 30–50s end to end | Prefer the tools that answer in one call: `list_all_datastores` already carries capacity, usage % and VM count, and `vsan_health` covers cluster health and disk groups together. Neither needs a per-object follow-up loop. |\n| Silently corrects a datastore name's case and reports on the wrong object | Resolve names through `list_all_datastores` first, and have the model echo the resolved name before acting. |\n| Recomputes usage percentages and gets them wrong | The \"report capacity in the units the tool returned\" rule. |\n| Treats \"already enabled\" as a failure and retries | It is a stated result. The response carries the HBA device and IQN. |\n| Reports a host as \"missing the LUN\" when that host was never read | `storage_device_paths` lists such hosts in `hosts_not_read` and sets `complete: false`; they are never in `not_seen_on`, and neither is any disk that lives inside one host. Require the model to name unread hosts as unknown. |\n| Calls a `standby` path a failure | Only `states_needing_attention` (dead/disabled) is a finding. `standby` is normal on active/passive arrays. |\n\n## Reporting results\n\nLocal-model compatibility is an explicit design constraint for this family, and\nthe evidence base is small. If you evaluate a model against this skill —\nQwen, Mistral, Granite, or anything else — a report of what worked and what did\nnot is genuinely useful:\n[github.com/vmware-skills/VMware-Storage/issues](https://github.com/vmware-skills/VMware-Storage/issues).\n\nFile v1.12.0:references/capabilities.md\n\n# VMware Storage Capabilities\n\nAll 11 MCP tools exposed by `vmware-storage-mcp`, organized by category.\n\n## Automation Level Reference\n\nEach operation is classified by autonomy level per the Enterprise Harness Engineering framework:\n\n| Level | Meaning | Agent autonomy | Examples in this skill |\n|:-:|---|---|---|\n| **L1** | Read-only, raw data | Always auto-run | `list_all_datastores`, `browse_datastore`, `scan_datastore_images`, `list_cached_images`, `storage_iscsi_status`, vSAN status queries |\n| **L2** | Read + analysis / recommendation | Always auto-run | datastore capacity analysis, image registry queries, iSCSI target health correlation |\n| **L3** | Single write — user must approve | Only after explicit confirmation; high-risk ops require double-confirm + `--dry-run` (see Confirm column) | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target`, vSAN cluster ops |\n| **L4** | Multi-step plan / apply workflow | Plan generation auto; apply gated by user approval | *(roadmap — multi-host iSCSI rollout, vSAN expansion plans)* |\n| **L5** | Auto-remediation from learned pattern | Pattern library only; requires `risk:low` + `reversible:true` + `repeatable:true` + signed approval | **PoC pattern (v1.5.16+)**: [`patterns/iscsi-target-stale-rescan.yaml`](../../../patterns/iscsi-target-stale-rescan.yaml) — scans for stale iSCSI devices (`devices_inaccessible_count > 0`, missing expected devices, or `last_rescan_age_minutes > 60`); action: invoke `storage_rescan` on the affected `(host, target)`; classified low-risk because the rescan is idempotent and non-destructive (no data, config, or VM state is modified). Schema only — **not yet enforced by the runtime**. |\n\n**Notes**:\n- L1/L2 tools are always safe for agents to call without confirmation.\n- L3 tools always pass through the `@vmware_tool` decorator: connection check → policy check → audit log → double-confirm.\n- L5 PoC pattern (`patterns/iscsi-target-stale-rescan.yaml`, v1.5.16+) is a **reference design**: it documents the candidate trigger / action / validation / circuit-breaker shape under `schema_version: 1` (see [vmware-policy auto-remediation pattern docs](https://github.com/vmware-skills/VMware-Policy/blob/main/docs/auto-remediation-patterns.md)). The pattern is `approval.status: poc_unsigned` and will only become live after `success_count_required: 5` + `failure_count_max: 0` + `distinct_operators_required: 2` + `days_observed: 90` are met and the pattern is signed.\n\n## Datastore (4 tools)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `list_all_datastores` | List datastores with capacity, usage %, VM count | `target` (string, optional) | Low | No |\n| `browse_datastore` | Browse files with optional path and glob pattern | `datastore` (string, **required**), `path` (string, optional), `pattern` (string, optional), `target` (string, optional) | Low | No |\n| `scan_datastore_images` | Find OVA/ISO/OVF/VMDK deployable images in a datastore | `datastore` (string, **required**), `target` (string, optional) | Low | No |\n| `list_cached_images` | Query local image registry with type/datastore filters | `image_type` (string, optional), `datastore` (string, optional) | Low | No |\n\n**List envelope**: all four return `{items, returned, limit, total, truncated, hint}` instead of a bare array, so an agent can tell a complete answer from a first page rather than inferring it (VMware-AIops issue #31). Each enumerates its collection in full — a PropertyCollector walk, a datastore browse task, or the on-disk registry — so `total` is the real count and `truncated` is always `false`. On error the tools return `{error, hint}` (a dict, not a one-element list).\n\n## iSCSI (5 tools)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `storage_iscsi_status` | Show adapter status, HBA device, IQN, configured send targets | `host` (string, **required**), `target` (string, optional) | Low | No |\n| `storage_iscsi_enable` | Enable software iSCSI adapter on a host | `host` (string, **required**), `confirm` (boolean, default: false — previews), `target` (string, optional) | Medium | Yes |\n| `storage_iscsi_add_target` | Add iSCSI send target (IP + port) and rescan storage | `host` (string, **required**), `address` (string, **required**), `port` (integer, default: 3260), `confirm` (boolean, default: false — previews), `target` (string, optional) | Medium | Yes |\n| `storage_iscsi_remove_target` | Remove iSCSI send target and rescan storage | `host` (string, **required**), `address` (string, **required**), `port` (integer, default: 3260), `confirm` (boolean, default: false — previews), `target` (string, optional) | Medium | Yes |\n| `storage_rescan` | Rescan all HBAs and VMFS volumes on a host | `host` (string, **required**), `confirm` (boolean, default: false — previews), `target` (string, optional) | Low | Yes |\n\n## vSAN (3 tools)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `vsan_health` | Cluster health summary with disk group details per host | `cluster` (string, **required**), `target` (string, optional) | Low | No |\n| `vsan_capacity` | Total/used/free capacity in GB and usage percentage | `cluster` (string, **required**), `target` (string, optional) | Low | No |\n| `vsan_efficiency` | Dedup + compression status (vSAN Management SDK) | `cluster_name` (string, **required**), `target` (string, optional) | Low | No |\n\n## Fibre Channel / multipath (2 tools, read-only)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `fc_adapter_list` | FC and FCoE HBAs per host: vmhba, model, driver, status, port type, WWPN/WWNN, `speed_reported` | `cluster` or `host` (optional; neither = every host on the target), `limit` (1-200, default 50), `offset`, `target` | Low | No |\n| `storage_device_paths` | Per-device (NAA) SCSI multipath state across the hosts of one scope: `shared`, `seen_by`, `not_seen_on`, `path_count_differs`, `states_needing_attention`, per-host path counts by state, working paths, adapters, PSP/SATP, VMFS datastores | exactly one of `cluster` / `host` / `datastore` (**required**); `device`, `adapter`, `only_differences`, `limit`, `offset`, `target` | Low | No |\n\nSource: each host's `config.storageDevice` (HBAs, SCSI LUNs, `multipathInfo`) and `config.fileSystemVolume.mountInfo`, fetched in one PropertyCollector call per scope. No SSH, no array or switch credentials, no rescans. Requested in [VMware-Storage#18](https://github.com/vmware-skills/VMware-Storage/issues/18).\n\n- **Unread is not empty.** A host whose storage view could not be read — `NoPermission`, not connected (vCenter keeps a lost host's last-known config, so it is not treated as current), or missing from vCenter's reply — is listed in `hosts_not_read` with the reason, `complete` is `false`, and that host is never counted in `not_seen_on` or `hosts_without_fc`.\n- **Observed state, not verdicts.** `states_needing_attention` holds only `dead` and `disabled`. `standby` is reported in `by_state` but not flagged (it is normal on active/passive arrays), and a path count does not prove independent fabrics.\n- **Only shared devices can be missing.** `not_seen_on` is filled only when `shared` is true: the device is reached over FC or iSCSI (judged by the path's adapter type, so a dead path that lost its transport still counts) or already seen by more than one host. A local-marked device is exempt even on a SAN — that is how a boot-from-SAN LUN zoned to one host is usually marked. A disk inside one host — local, or a SAS/NVMe drive ESXi marks non-local — is never reported missing elsewhere. `mpx.*` names, non-disk LUNs (CD-ROM) and unresolved LUNs are per-host and never merged across hosts, since every host can have its own `mpx.vmhba0:C0:T0:L0`. A side effect: an array LUN that has no NAA identifier and is named `mpx.*` is shown once per host rather than as one shared device. Each path row carries `protocol` (`fc`, `iscsi` or null).\n- **`adapter`** matches by vmhba name; in a cluster scope `vmhba2` can be a different card on each host.\n- **`complete`** is false when any host was not read, or when a datastore's backing devices are unknown (no readable host reports the VMFS volume mounted).\n- **`speed_reported`** is the raw vSphere value. The API documents bits per second, but hosts commonly report Gbit/s (e.g. `16`), so it is not converted.\n- **Scope**: `storage_device_paths` requires one scope and refuses to read every host at once — multipath data is large on estates with hundreds of hosts. Per-path detail is returned only when `device` or `datastore` is given.\n- **Not covered**: NVMe-oF namespaces may not appear (they are not in `multipathInfo`); zoning, array masking and switch health are out of scope.\n- **Privileges**: reads host configuration only. Expected to work with the Read-Only role; not yet validated against a restricted account.\n- **Typical response**: `fc_adapter_list` ~80 tokens per adapter; `storage_device_paths` ~120 tokens per device per host in summary form, 2–3× that with per-path detail.\n\n## Risk Level Definitions\n\n| Level | Meaning | Examples |\n|-------|---------|---------|\n| **Low** | Read-only query, no state change | `list_all_datastores`, `browse_datastore`, `vsan_health`, `storage_iscsi_status`, `storage_rescan` |\n| **Medium** | State change affecting storage configuration, but recoverable | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target` |\n\n## Tool Counts by Risk Level\n\n| Risk | Count | Tools |\n|------|:-----:|-------|\n| Low | 11 | All read-only tools + `storage_rescan` |\n| Medium | 3 | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target` |\n\n> Note: `storage_rescan` triggers a host-level HBA rescan which is non-destructive (discovery only) and classified as Low risk. The iSCSI write tools (`enable`, `add_target`, `remove_target`) are Medium risk because they modify the host's iSCSI configuration, but changes are reversible.\n\n## Input Validation\n\n| Parameter | Validation | Error on Invalid |\n|-----------|-----------|-----------------|\n| `address` (IP) | `ipaddress.ip_address()` — accepts IPv4 and IPv6 | `ISCSIError: Invalid IP address` |\n| `port` | Integer in range 1-65535 | `ISCSIError: Port must be 1-65535` |\n| `host` | Looked up by exact name match in vSphere inventory | `HostNotFoundError` |\n| `cluster` | Looked up by exact name match in vSphere inventory | `VSANError: Cluster not found` |\n| `datastore` | Looked up by exact name match (case-sensitive) | `Datastore not found` |\n\n## Audit Coverage\n\nAll 14 tools are wrapped with `@vmware_tool` from vmware-policy, which provides:\n\n- **Pre-execution**: Policy rule check against `~/.vmware/rules.yaml` (deny rules, maintenance windows)\n- **Post-execution**: Audit log entry written to `~/.vmware/audit.db` (SQLite WAL mode)\n- **Input sanitization**: All vSphere API response text processed through `sanitize()` (truncation + control character cleanup)\n\n## Read/Write Split\n\n| Type | Count | Tools |\n|------|:-----:|-------|\n| Read | 10 | `list_all_datastores`, `browse_datastore`, `scan_datastore_images`, `list_cached_images`, `storage_iscsi_status`, `vsan_health`, `vsan_capacity`, `vsan_efficiency`, `fc_adapter_list`, `storage_device_paths` |\n| Write | 4 | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target`, `storage_rescan` |\n\n> Write tools require explicit parameters (host name, IP address) and support `--dry-run` in CLI mode. Over MCP they preview by default: without `confirm: true` they return `blast_radius` and change nothing. All write operations are audit-logged with timestamp, user, target, operation, parameters, and result.\n\n## Connection Requirements\n\n| Requirement | Datastore Tools | iSCSI Tools | vSAN Tools |\n|-------------|:---------------:|:-----------:|:----------:|\n| vCenter connection | Required | Not required (direct ESXi OK) | Required |\n| ESXi host access | Via vCenter | Direct or via vCenter | Via vCenter |\n| pyVmomi | Required | Required | Required |\n| vSAN SDK | Not required | Not required | Recommended (for full health) |\n\n## Runtime Requirements\n\n| Requirement | Minimum | Notes |\n|-------------|---------|-------|\n| Python | 3.10+ | Lowered from 3.11 in v1.5.27 for Goose sandbox / Ubuntu 22.04 compatibility. Tested on 3.10 / 3.11 / 3.12. |\n| OS | macOS, Linux | stdio MCP transport — no network listener required |\n\nFile v1.12.0:references/cli-reference.md\n\n# CLI Reference\n\nComplete command reference for `vmware-storage` CLI.\n\n## Global Options\n\nAll commands accept these options:\n\n| Option | Description |\n|--------|-------------|\n| `--target <name>` | Target name from `~/.vmware-storage/config.yaml` (defaults to first target) |\n| `--config <path>` | Override config file path |\n| `--help` | Show command help |\n\n## Datastore Commands\n\n### `datastore list`\n\nList all datastores with capacity, usage, and VM count.\n\n```bash\nvmware-storage datastore list\nvmware-storage datastore list --target my-vcenter\n```\n\nOutput columns: Name, Type, Total GB, Free GB, Usage %, VMs.\nUsage above 85% is highlighted in red.\n\n### `datastore browse`\n\nBrowse files in a datastore directory. Supports glob pattern filtering.\n\n```bash\n# Browse root of a datastore\nvmware-storage datastore browse datastore01\n\n# Browse a subdirectory\nvmware-storage datastore browse datastore01 --path \"iso-images\"\n\n# Filter by pattern\nvmware-storage datastore browse datastore01 --pattern \"*.ova\"\nvmware-storage datastore browse datastore01 --path \"templates\" --pattern \"*.iso\"\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `ds_name` | Yes | - | Datastore name (case-sensitive) |\n| `--path` | No | `\"\"` (root) | Subdirectory path within the datastore |\n| `--pattern` | No | `\"*\"` | Glob pattern to filter files |\n\nOutput: JSON array of file objects with `name`, `size_mb`, `type`, `modified`, `ds_path`.\n\n### `datastore scan-images`\n\nScan a datastore for deployable images (OVA, ISO, OVF, VMDK).\n\n```bash\nvmware-storage datastore scan-images datastore01\nvmware-storage datastore scan-images datastore01 --target prod-vcenter\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `ds_name` | Yes | - | Datastore name |\n\nScans for patterns: `*.ova`, `*.ovf`, `*.iso`, `*.vmdk`. Results are sorted by name.\n\n## iSCSI Commands\n\n### `iscsi enable`\n\nEnable the software iSCSI adapter on an ESXi host.\n\n```bash\nvmware-storage iscsi enable esxi-01\nvmware-storage iscsi enable esxi-01 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\n**Safety**: Requires double confirmation (two prompts). If the adapter is already enabled, returns current HBA device and IQN without making changes.\n\n### `iscsi status`\n\nShow iSCSI adapter status and configured send targets.\n\n```bash\nvmware-storage iscsi status esxi-01\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n\nOutput: JSON with `enabled`, `hba_device`, `iqn`, and `send_targets` (list of address/port pairs).\n\n### `iscsi add-target`\n\nAdd an iSCSI send target to a host and automatically rescan storage.\n\n```bash\nvmware-storage iscsi add-target esxi-01 192.168.1.100\nvmware-storage iscsi add-target esxi-01 10.0.0.50 --port 3261\nvmware-storage iscsi add-target esxi-01 192.168.1.100 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `address` | Yes | - | iSCSI target IP address (validated) |\n| `--port` | No | `3260` | iSCSI target port (1-65535) |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\n**Safety**: Requires double confirmation. IP address and port are validated before any API call. If the target is already configured, returns without making changes. After adding, automatically rescans all HBAs and VMFS volumes.\n\n### `iscsi remove-target`\n\nRemove an iSCSI send target from a host and automatically rescan storage.\n\n```bash\nvmware-storage iscsi remove-target esxi-01 192.168.1.100\nvmware-storage iscsi remove-target esxi-01 10.0.0.50 --port 3261\nvmware-storage iscsi remove-target esxi-01 192.168.1.100 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `address` | Yes | - | iSCSI target IP address |\n| `--port` | No | `3260` | iSCSI target port |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\n**Safety**: Requires double confirmation. Raises an error if the target is not found (prevents accidental no-ops). Automatically rescans after removal.\n\n### `iscsi rescan`\n\nRescan all HBAs and VMFS volumes on an ESXi host.\n\n```bash\nvmware-storage iscsi rescan esxi-01\nvmware-storage iscsi rescan esxi-01 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\nCalls both `RescanAllHba()` and `RescanVmfs()` on the host storage system.\n\n## vSAN Commands\n\n### `vsan health`\n\nGet vSAN cluster health summary including disk group details.\n\n```bash\nvmware-storage vsan health Cluster-Prod\nvmware-storage vsan health Cluster-Prod --target my-vcenter\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `cluster_name` | Yes | - | Name of the vSAN-enabled cluster |\n\nOutput: JSON with `vsan_enabled`, `overall_health`, `host_count`, `disk_groups` (per-host cache/capacity disk info).\n\n### `vsan capacity`\n\nGet vSAN capacity overview (total/used/free) for a cluster.\n\n```bash\nvmware-storage vsan capacity Cluster-Prod\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `cluster_name` | Yes | - | Name of the vSAN-enabled cluster |\n\nOutput: JSON with `total_gb`, `used_gb`, `free_gb`, `usage_pct`, `datastore_name`.\n\n## Fibre Channel / Multipath Commands (read-only)\n\n### `paths fc-adapters`\n\nList FC and FCoE HBAs per host with WWPN/WWNN, port type, status and the raw reported speed.\n\n```bash\nvmware-storage paths fc-adapters --cluster Cluster-Prod\nvmware-storage paths fc-adapters --host esxi-01.example.com\nvmware-storage paths fc-adapters            # every host on the target\n```\n\n| Option | Required | Default | Description |\n|--------|:--------:|---------|-------------|\n| `--cluster` | No | - | Cluster name |\n| `--host` | No | - | ESXi host name |\n| `--limit` / `--offset` | No | 50 / 0 | Paging (limit 1-200) |\n\nOutput: list envelope plus `hosts_without_fc` and `hosts_not_read` (hosts that were not read are never reported as having no FC HBA).\n\n### `paths devices`\n\nPer-device SCSI multipath state across the hosts of one scope.\n\n```bash\nvmware-storage paths devices --datastore ds-fc-01                     # dead/disabled paths behind a datastore\nvmware-storage paths devices --cluster Cluster-Prod --only-differences # path counts differ, or a shared device is missing\nvmware-storage paths devices --cluster Cluster-Prod --device naa.60060e80123456\nvmware-storage paths devices --host esxi-01 --adapter vmhba2          # what depends on one HBA\n```\n\n| Option | Required | Default | Description |\n|--------|:--------:|---------|-------------|\n| `--cluster` / `--host` / `--datastore` | Exactly one | - | Scope |\n| `--device` | No | - | Canonical name (`naa.…`) or display name, case-insensitive |\n| `--adapter` | No | - | vmhba name; adds `paths_via_adapter` and `only_paths_via_adapter` per host. Matched by name: in a cluster scope `vmhba2` can be a different card on each host |\n| `--only-differences` | No | false | Only devices whose visibility or path count differs across the hosts read |\n| `--limit` / `--offset` | No | 50 / 0 | Paging over devices (limit 1-200) |\n\nOutput: list envelope of devices (those with dead/disabled paths first), plus `summary`, `hosts_read`, `hosts_not_read`, `complete`, `scope_note` and `note`. Path states are reported as vSphere reports them; `standby` is not flagged.\n\n## Diagnostics\n\n### `doctor`\n\nRun environment and connectivity diagnostics.\n\n```bash\nvmware-storage doctor\nvmware-storage doctor --skip-auth\n```\n\n| Option | Description |\n|--------|-------------|\n| `--skip-auth` | Skip the vSphere authentication check (useful when vCenter is unreachable) |\n\nChecks performed:\n1. Config file exists (`~/.vmware-storage/config.yaml`)\n2. `.env` file exists with correct permissions (600)\n3. Targets are configured in config\n4. Network connectivity to all targets (TCP port check with 5s timeout)\n5. vSphere authentication (actual login via pyVmomi)\n6. MCP server module loads successfully\n\n## Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| `0` | Success |\n| `1` | Operation failed or doctor check failed |\n\n## Environment Variables\n\n| Variable | Description |\n|----------|-------------|\n| `VMWARE_STORAGE_CONFIG` | Override config file path (used by MCP server) |\n| `VMWARE_<TARGET>_PASSWORD` | Password for a target (e.g., `VMWARE_MY_VCENTER_PASSWORD`) |\n\nFile v1.12.0:references/setup-guide.md\n\n# Setup Guide\n\nComplete setup and security guide for `vmware-storage`.\n\n## Prerequisites\n\n- Python 3.10+\n- vCenter Server 6.7+ or standalone ESXi 6.7+\n- Network access to vCenter/ESXi on port 443 (or custom port)\n\n## Installation\n\n### Via uv (recommended)\n\n```bash\nuv tool install vmware-storage==1.12.0\n```\n\n### Via pip\n\n```bash\npip install vmware-storage==1.12.0\n```\n\n### From source\n\n```bash\ngit clone --branch v1.12.0 https://github.com/vmware-skills/VMware-Storage.git\ncd VMware-Storage\npip install -e .\n```\n\n## Configuration\n\n### 1. Create config directory\n\n```bash\nmkdir -p ~/.vmware-storage\n```\n\n### 2. Create config.yaml\n\n```bash\ncp config.example.yaml ~/.vmware-storage/config.yaml\n```\n\nEdit `~/.vmware-storage/config.yaml`:\n\n```yaml\ntargets:\n  - name: my-vcenter          # Target identifier (used in CLI --target flag)\n    host: vcenter.example.com  # Hostname or IP\n    username: administrator@vsphere.local\n    type: vcenter              # \"vcenter\" or \"esxi\"\n    port: 443\n    verify_ssl: false          # Set true if using valid certs\n    environment: production    # Which environment this target is — see below\n\n  - name: esxi-standalone\n    host: 10.0.0.50\n    username: root\n    type: esxi\n    port: 443\n    verify_ssl: false\n    environment: lab\n\nnotify:\n  webhook_url: \"\"              # Optional: webhook for notifications\n```\n\nThe first target in the list is the default (used when `--target` is not specified).\n\n#### `environment` — declare which environment each target is\n\n`environment:` is an optional free-form label. Policy scopes its rules by this\nvalue, so an environment-scoped `deny` rule in `~/.vmware/rules.yaml` can match\non it — for example, to freeze state-changing writes (`iscsi enable`,\n`iscsi add-target`, `iscsi remove-target`, `rescan`) on `production`. A target\nwith no label is simply not matched by such a rule.\n\nAny label works (`production`, `staging`, `lab`, or your own); the target's\n*name* is not used for scoping. Read-only operations are never affected. Run\n`vmware-audit policy` to see the rules actually in force.\n\n### 3. Create .env for credentials\n\nPasswords are **never stored in config.yaml**. They must be set as environment variables via the `.env` file.\n\n```bash\necho \"VMWARE_MY_VCENTER_PASSWORD=your_password\" > ~/.vmware-storage/.env\necho \"VMWARE_ESXI_STANDALONE_PASSWORD=root_password\" >> ~/.vmware-storage/.env\nchmod 600 ~/.vmware-storage/.env\n```\n\n**Naming convention**: `VMWARE_<TARGET_NAME_UPPER>_PASSWORD` where `<TARGET_NAME_UPPER>` is the target `name` from config.yaml, uppercased, with hyphens replaced by underscores.\n\nExamples:\n| Target name | Environment variable |\n|-------------|---------------------|\n| `my-vcenter` | `VMWARE_MY_VCENTER_PASSWORD` |\n| `esxi-standalone` | `VMWARE_ESXI_STANDALONE_PASSWORD` |\n| `prod01` | `VMWARE_PROD01_PASSWORD` |\n\n### 4. Verify setup\n\n```bash\nvmware-storage doctor\n```\n\nThis runs six checks: config file, .env file, targets, network connectivity, authentication, and MCP server module.\n\nUse `--skip-auth` if vCenter is temporarily unreachable:\n\n```bash\nvmware-storage doctor --skip-auth\n```\n\n## MCP Server Configuration\n\n### Claude Code / Claude Desktop\n\nAdd to your MCP config (`~/.claude.json` or Claude Desktop settings):\n\n```json\n{\n  \"mcpServers\": {\n    \"vmware-storage\": {\n      \"command\": \"vmware-storage\",\n      \"args\": [\"mcp\"],\n      \"env\": {\n        \"VMWARE_STORAGE_CONFIG\": \"~/.vmware-storage/config.yaml\"\n      }\n    }\n  }\n}\n```\n\n> v1.5.15+ recommends the single-command form `vmware-storage mcp`. Pre-1.5.15 used\n> `uvx --from vmware-storage vmware-storage-mcp`, which still works but re-resolves from <!-- install-pin: historical -->\n> PyPI on each launch and breaks behind corporate TLS proxies. The legacy\n> `vmware-storage-mcp` entry point is also kept for backward compatibility.\n\n### Goose\n\nAdd to `~/.config/goose/config.yaml`:\n\n```yaml\nextensions:\n  vmware-storage:\n    type: stdio\n    cmd: vmware-storage\n    args:\n      - mcp\n    env:\n      VMWARE_STORAGE_CONFIG: \"~/.vmware-storage/config.yaml\"\n```\n\n### Docker\n\n```bash\ndocker compose up -d\n```\n\nOr run manually:\n\n```bash\ndocker run -d \\\n  -v ~/.vmware-storage:/root/.vmware-storage:ro \\\n  -e VMWARE_STORAGE_CONFIG=/root/.vmware-storage/config.yaml \\\n  vmware-storage\n```\n\n### Password obfuscation at rest\n\nOn first load, any plaintext `*_PASSWORD` value in `.env` is automatically\nrewritten to a grep-safe `b64:<encoded>` form and decoded transparently at\nruntime, so a casual `grep` of the file no longer reveals the password. Values\nare read and written through python-dotenv's own parser, so the stored secret\nnever drifts from what you configured (quotes, inline comments, and trailing\nwhitespace are handled correctly).\n\n> **This is obfuscation, not encryption.** Anyone who can read the file can\n> still decode it. For real secrecy at rest, do not store the password in `.env`\n> at all — inject it from a secret manager (HashiCorp Vault, CyberArk, AWS\n> Secrets Manager, or a Kubernetes Secret) into the `*_PASSWORD` environment\n> variable at process start. The code reads the env var either way.\n\n## Security Details\n\n> **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom.\n\n### Credential Safety\n\n- Passwords are **only loaded from environment variables** (via `.env` file), never from `config.yaml`\n- The `.env` file permissions are checked at startup; a warning is logged if permissions are wider than `600` (owner read/write only)\n- The `doctor` command verifies `.env` permissions and reports failures\n\n### Audit Logging\n\nAll operations are logged to `~/.vmware/audit.db` (SQLite WAL mode, via vmware-policy).\n\nEach audit entry records:\n- **timestamp**: UTC ISO 8601\n- **target**: Which vCenter/ESXi was acted on\n- **operation**: What was done (e.g., `iscsi_enable`, `iscsi_add_target`, `query`)\n- **resource**: What resource was affected (host name, datastore name)\n- **parameters**: Full parameter set passed to the operation\n- **before_state / after_state**: State snapshots (when available)\n- **result**: Operation outcome\n- **user**: OS username who initiated the operation\n\nExample audit entry:\n\n```json\n{\n  \"timestamp\": \"2026-03-25T10:30:00+00:00\",\n  \"target\": \"my-vcenter\",\n  \"operation\": \"iscsi_add_target\",\n  \"resource\": \"esxi-01\",\n  \"parameters\": {\"host_name\": \"esxi-01\", \"address\": \"10.0.0.100\", \"port\": 3260},\n  \"before_state\": {},\n  \"after_state\": {},\n  \"result\": \"iSCSI target 10.0.0.100:3260 added to host 'esxi-01' and storage rescanned.\",\n  \"user\": \"admin\"\n}\n```\n\nRead-only operations (list, browse, scan, status, health, capacity) are also logged with `operation: \"query\"` for complete traceability.\n\n### Read-only access\n\nTo run the agent read-only, give it a read-only vCenter service account (RBAC) — enforced at the platform.\n\n### Double Confirmation on Destructive Operations\n\nCLI write commands require two separate confirmation prompts before executing:\n\n1. First prompt: \"Are you sure?\" (default: No)\n2. Second prompt: \"This modifies host storage configuration. Confirm again?\" (default: No)\n\nBoth must be answered `y` for the operation to proceed. This applies to:\n- `iscsi enable`\n- `iscsi add-target`\n- `iscsi remove-target`\n\n### Dry-Run Mode\n\nAll write commands support `--dry-run` to preview what would happen without making changes:\n\n```bash\nvmware-storage iscsi enable esxi-01 --dry-run\n# Output: [DRY-RUN] Would enable software iSCSI on host 'esxi-01'\n\nvmware-storage iscsi add-target esxi-01 10.0.0.100 --dry-run\n# Output: [DRY-RUN] Would add iSCSI target 10.0.0.100:3260 to host 'esxi-01' and rescan\n```\n\n### Prompt Injection Defense\n\nDatastore file names and paths returned from vSphere are sanitized before output via the `_sanitize()` function:\n\n- Strips C0/C1 control characters (U+0000-U+0008, U+000B, U+000C, U+000E-U+001F, U+007F-U+009F)\n- Preserves newlines and tabs\n- Truncates to 500 characters maximum\n\nThis prevents malicious file names on datastores from injecting prompts or instructions when the data flows to downstream LLM agents.\n\n### Input Validation\n\n- **IP addresses**: Validated via Python's `ipaddress.ip_address()` before any iSCSI operation\n- **Ports**: Validated to be in range 1-65535\n- **Datastore names**: Case-sensitive lookup; returns a clear error if not found\n- **Host names**: Looked up via vSphere inventory; raises `HostNotFoundError` if not found\n- **Cluster names**: Looked up via vSphere inventory; raises `VSANError` if not found\n\n### Transport Security\n\n- The MCP server uses **stdio transport** (local only) -- no network listener is opened\n- vSphere connections use SSL/TLS on port 443 by default\n- SSL certificate verification can be enabled per-target via `verify_ssl: true` in config.yaml\n\n### What This Skill Cannot Do\n\nThis skill has **no VM operations**. It cannot:\n- Power on, power off, or restart VMs\n- Create, clone, or delete VMs\n- Deploy OVA/OVF templates\n- Run commands inside guest VMs\n- Modify VM configuration (CPU, memory, network)\n\nFor VM operations, use `vmware-aiops`.\n\n## Multi-Target Setup\n\nYou can configure multiple vCenter/ESXi targets and switch between them:\n\n```yaml\ntargets:\n  - name: prod-vcenter\n    host: vcenter-prod.example.com\n    username: svc-storage@vsphere.local\n    type: vcenter\n\n  - name: dev-vcenter\n    host: vcenter-dev.example.com\n    username: administrator@vsphere.local\n    type: vcenter\n\n  - name: lab-esxi\n    host: 10.0.1.50\n    username: root\n    type: esxi\n```\n\n```bash\n# Uses first target (prod-vcenter) by default\nvmware-storage datastore list\n\n# Explicitly target dev\nvmware-storage datastore list --target dev-vcenter\n\n# Target standalone ESXi\nvmware-storage iscsi status lab-esxi --target lab-esxi\n```\n\n## Version Compatibility\n\n| vSphere / VCF | Support | Notes |\n|---------|---------|-------|\n| VCF 9.1 / vSphere 9.1 | Full | Released 2026-05-12. pyVmomi+vSAN SDK `<10.0` works via SOAP. |\n| VCF 9.0 / vSphere 9.0 | Full | pyVmomi 8.0.3+ with bundled vSAN SDK connects to vSphere 9. |\n| 8.0 | Full | vSAN SDK built into pyVmomi 8.0.3+ |\n| 7.0 | Full | All storage APIs work |\n| 6.7 | Compatible | iSCSI + datastore features work; vSAN limited |\n\n## File Locations\n\n| File | Purpose |\n|------|---------|\n| `~/.vmware-storage/config.yaml` | Connection targets and settings |\n| `~/.vmware-storage/.env` | Passwords (chmod 600) |\n| `~/.vmware/audit.db` | Operation audit trail (SQLite WAL, via vmware-policy) |\n| `~/.vmware-storage/image_registry.json` | Cached image scan results |\n| `~/.vmware-storage/scan.log` | Scanner log output |\n\nFile v1.12.0:skill-card.md\n\n## Description:\n\nvmware-storage helps agents manage VMware vSphere storage, including datastores, deployable-image scans, iSCSI targets, vSAN health and capacity, and Fibre Channel or multipath diagnostics.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and infrastructure operators use this skill to inspect and manage VMware storage resources, including datastore browsing, deployable image discovery, iSCSI configuration, vSAN checks, and Fibre Channel or multipath diagnostics.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The documented default TLS setting could expose privileged vCenter or ESXi credentials.\n\nMitigation: Set target configs to verify_ssl: true or provide a trusted CA before using the skill against sensitive environments.\n\nRisk: The skill requires VMware management credentials and can perform storage write operations.\n\nMitigation: Use least-privilege service accounts, inject secrets from a secret manager when possible, and review the previewed blast radius before approving write operations.\n\nRisk: Removing an iSCSI target or approving other storage writes can affect datastore or LUN availability.\n\nMitigation: Treat iSCSI remove-target and other write operations as high-impact; approve them only after confirming paths, affected devices, and operational intent.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/zw008/skills/vmware-storage)\n- [VMware-Storage homepage](https://github.com/vmware-skills/VMware-Storage)\n- [Setup Guide](references/setup-guide.md)\n- [Capabilities](references/capabilities.md)\n- [CLI Reference](references/cli-reference.md)\n- [Agent Guardrails](references/agent-guardrails.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline shell commands, configuration snippets, and structured operational guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May guide agents to invoke local CLI or MCP tools that return text or JSON-like operational results.]\n\n## Skill Version(s):\n\n1.12.0 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.12.0:evals/evals.json\n\n{\n  \"skill_name\": \"vmware-storage\",\n  \"evals\": [\n    {\n      \"id\": 1,\n      \"prompt\": \"Add a new iSCSI target 10.0.1.50 on host esxi-01 and verify the new LUNs appear\",\n      \"expected_output\": \"iSCSI target added, storage rescanned, new datastores visible\",\n      \"files\": [],\n      \"expectations\": [\n        \"Uses storage_iscsi_enable if adapter not enabled\",\n        \"Uses storage_iscsi_add_target with correct IP\",\n        \"Uses storage_rescan or verifies with list_all_datastores\"\n      ]\n    },\n    {\n      \"id\": 2,\n      \"prompt\": \"Check vSAN health on cluster Production and show me the capacity breakdown\",\n      \"expected_output\": \"vSAN health status and capacity details\",\n      \"files\": [],\n      \"expectations\": [\n        \"Uses vsan_health for health summary\",\n        \"Uses vsan_capacity for capacity breakdown\",\n        \"Shows total/used/free in human-readable format\"\n      ]\n    },\n    {\n      \"id\": 3,\n      \"prompt\": \"Find all OVA files on datastore1 that I can use for deployment\",\n      \"expected_output\": \"List of deployable OVA images\",\n      \"files\": [],\n      \"expectations\": [\n        \"Uses scan_datastore_images or browse_datastore with OVA filter\",\n        \"Returns file paths suitable for deploy_vm_from_ova\"\n      ]\n    }\n  ]\n}\n\nArchive v1.11.0: 8 files, 27945 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (8820b), references/capabilities.md (12615b), references/cli-reference.md (8998b), references/setup-guide.md (10641b), skill-card.md (2728b), SKILL.md (20249b), _meta.json (134b)\n\nFile v1.11.0:SKILL.md\n\n---\nname: vmware-storage\ndescription: >\n  Use this skill whenever the user needs to manage VMware storage — datastores, iSCSI targets, and vSAN clusters.\n  Directly handles: browse datastores, scan for deployable images (OVA/ISO), configure iSCSI adapters and targets, check vSAN health and capacity, read-only Fibre Channel HBA/WWPN inventory and multipath path state.\n  Always use this skill for \"list datastores\", \"add iSCSI target\", \"check vSAN health\", \"browse datastore files\", \"scan for OVA images\", \"dead paths\", \"FC HBA WWPN\", or any storage-related VMware task.\n  Do NOT use for VM lifecycle operations (use vmware-aiops), NSX networking (use vmware-nsx), or Kubernetes clusters (use vmware-vks).\n  For load balancing/AVI/AKO use vmware-avi.\ninstaller:\n  kind: uv\n  package: vmware-storage\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"vmware-storage\",\"uvx\"]},\"optional\":{\"env\":[\"VMWARE_STORAGE_CONFIG\",\"VMWARE_<TARGET>_PASSWORD\",\"VMWARE_<TARGET>_USERNAME\",\"VMWARE_AUDIT_APPROVED_BY\"],\"bins\":[\"vmware-policy\"]},\"homepage\":\"https://github.com/vmware-skills/VMware-Storage\",\"emoji\":\"🗄️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  vmware-policy auto-installed as Python dependency (provides @vmware_tool decorator and audit logging). All write operations audited to ~/.vmware/audit.db.\n  Credentials: Each vCenter/ESXi target requires a per-target password env var in ~/.vmware-storage/.env following the pattern VMWARE_<TARGET_NAME_UPPER>_PASSWORD (e.g., target \"my-vcenter\" → VMWARE_MY_VCENTER_PASSWORD). No webhooks or outbound network calls — this skill is local-only (stdio MCP + vSphere API). Audit logs written to ~/.vmware/audit.db (SQLite WAL, local only).\n---\n\n# VMware Storage\n\n> **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom. Source code is publicly auditable at [github.com/vmware-skills/VMware-Storage](https://github.com/vmware-skills/VMware-Storage) under the MIT license.\n\nVMware vSphere storage management — 14 MCP tools for datastores, iSCSI, vSAN, and Fibre Channel / multipath diagnostics.\n\n> Split from vmware-aiops for lighter context and local model compatibility.\n> **Companion skills**: [vmware-aiops](https://github.com/vmware-skills/VMware-AIops) (VM lifecycle), [vmware-monitor](https://github.com/vmware-skills/VMware-Monitor) (read-only monitoring), [vmware-vks](https://github.com/vmware-skills/VMware-VKS) (Tanzu Kubernetes), [vmware-nsx](https://github.com/vmware-skills/VMware-NSX) (NSX networking), [vmware-nsx-security](https://github.com/vmware-skills/VMware-NSX-Security) (DFW/firewall), [vmware-aria](https://github.com/vmware-skills/VMware-Aria) (metrics/alerts/capacity), [vmware-avi](https://github.com/vmware-skills/VMware-AVI) (AVI/ALB/AKO), [vmware-harden](https://github.com/vmware-skills/VMware-Harden) (compliance baselines).\n> | [vmware-pilot](../vmware-pilot/SKILL.md) (workflow orchestration) | [vmware-policy](../vmware-policy/SKILL.md) (audit/policy)\n\n## What This Skill Does\n\n| Category | Tools | Count |\n|----------|-------|:-----:|\n| **Datastore** | list all datastores, browse files, scan for OVA/ISO/OVF/VMDK images, list cached images | 4 |\n| **iSCSI** | enable adapter, show status, add target, remove target, rescan HBAs | 5 |\n| **vSAN** | cluster health summary, capacity overview (total/used/free), data-efficiency (dedup/compression) | 3 |\n| **FC / multipath** (read-only) | FC HBA inventory with WWPN/WWNN; per-device path state across hosts, datastore backing devices, path-count differences across hosts | 2 |\n\n## Quick Install\n\n```bash\nuv tool install vmware-storage==1.11.0\nvmware-storage init      # guided setup: writes config + .env (chmod 600, password grep-safe), then verifies\nvmware-storage doctor\n```\n\n## When to Use This Skill\n\n- Browse datastore files or scan for deployable images (OVA/ISO/VMDK)\n- Configure iSCSI: enable adapter, add/remove send targets, rescan storage\n- Check vSAN cluster health and capacity\n- Fibre Channel: list HBAs and WWPNs, find dead/disabled paths, compare path counts across a cluster, map a datastore to its devices\n- Any storage-focused VMware operation\n\n**Use companion skills for**:\n- VM lifecycle, deployment, guest ops → `vmware-aiops`\n- Inventory, health, alarms, events → `vmware-monitor`\n- Tanzu Kubernetes → `vmware-vks`\n- Load balancing, AVI/ALB, AKO, Ingress → `vmware-avi`\n\n## Related Skills — Skill Routing\n\n| User Intent | Recommended Skill |\n|-------------|-------------------|\n| Read-only monitoring, alarms, events | **vmware-monitor** |\n| Storage: iSCSI, vSAN, datastores | **vmware-storage** ← this skill |\n| VM lifecycle, deployment, guest ops | **vmware-aiops** |\n| Tanzu Kubernetes (vSphere 8.x+) | **vmware-vks** |\n| NSX networking: segments, gateways, NAT | **vmware-nsx** |\n| NSX security: DFW rules, security groups | **vmware-nsx-security** |\n| Aria Ops: metrics, alerts, capacity planning | **vmware-aria** |\n| Multi-step workflows with approval | **vmware-pilot** |\n| Compliance baselines (CIS / 等保 / PCI-DSS), drift detection, LLM remediation advisor | **vmware-harden** (`uv tool install vmware-harden`) |\n| Load balancer, AVI, ALB, AKO, Ingress | **vmware-avi** (`uv tool install vmware-avi`) |\n| Audit log query | **vmware-policy** (`vmware-audit` CLI) |\n\n## Common Workflows\n\n### Set Up iSCSI Storage on a Host\n\n**Pre-flight (judgment)**:\n- Network reachability: `vmkping <iscsi-target-ip>` from the ESXi host must succeed BEFORE adding the target. Adding an unreachable target leaves the host in a degraded state, retrying forever.\n- Adapter sanity: `iscsi status` first — if already enabled, do not \"re-enable\"; just add the target.\n- Idempotency: `add-target` is idempotent (re-adding same IP is a no-op), but `remove-target` is not safely reversible mid-IO. Always verify no LUNs from this target are in use before removing.\n- Existing targets: list them first; some sites add targets one-per-host while others use cluster-wide. Check site convention.\n\n**Steps**:\n1. `iscsi status esxi-01` → confirm adapter state and existing targets\n2. `iscsi enable esxi-01 --dry-run` then real (skip if already enabled)\n3. `iscsi add-target esxi-01 <ip> --dry-run` then real (auto-rescans on success)\n4. `iscsi status esxi-01` again → confirm target listed AND devices appearing\n5. If devices missing 30+ sec after add: `iscsi rescan esxi-01` once more, then check ESXi-side `vmkping` and target ACL\n\n### Find Deployable Images Across Datastores\n\n**Judgment**: image search is read-only and safe, but blind scanning of every datastore is slow on large estates. Filter first.\n\n1. `datastore list` → get the inventory; ignore datastores marked `inaccessible` or low free space\n2. `datastore scan-images <ds>` on the datastore most likely to hold images (typically named `iso-*`, `templates`, or central `nfs-shared`)\n3. If unsure where images live: scan multiple in parallel via separate calls; results are cached in the local registry\n4. `datastore browse <ds> --pattern \"*.iso\"` for ad-hoc searches; pattern is glob, not regex\n5. **If datastore not found**: name is case-sensitive. `datastore list --target <vc>` to verify exact spelling.\n\nFor filtered queries against the cache: use `list_cached_images` MCP tool with `image_type` and `datastore` parameters — avoids re-scanning.\n\n### vSAN Health Assessment\n\n**Judgment**: vSAN problems often masquerade as vSphere problems and vice-versa. Check both planes — if vSAN is healthy but VMs are slow, the issue is at the compute or network layer, not storage.\n\n1. `vsan health <cluster>` → look beyond green/red — check disk group state, network partitioning, and cluster member counts. A \"yellow\" disk group is the early warning of a failure.\n2. `vsan capacity <cluster>` → utilization > 70% triggers slack-space risk; > 80% impedes resync; never let prod cross 80%.\n3. Cross-check `vmware-monitor health alarms` for vSAN-related alarms (HCL warnings, network anomalies)\n4. **If vSAN not enabled** on this cluster: check cluster type via `vmware-monitor inventory clusters`; vSAN is opt-in, not default\n5. For deep investigation, follow [`references/investigation-protocol.md`](../vmware-aria/skills/vmware-aria/references/investigation-protocol.md) (in companion skill) — vSAN issues frequently fail the Mechanism criterion (capacity is correlated, not causal)\n\n### Check Fibre Channel Paths\n\n**Judgment**: report what vSphere observed, not a verdict. `standby` paths are normal on active/passive arrays, and equal path counts do not prove two independent fabrics. Zoning, array masking and switch health are out of scope.\n\n1. `paths devices --datastore <ds>` → dead/disabled paths behind one datastore, per host (devices needing attention sort first)\n2. `paths devices --cluster <c> --only-differences` → shared devices some hosts do not see, or see through a different number of paths; each host's `paths_total` shows which has fewer\n3. `paths devices --host <h> --adapter vmhba2` → what depends on one HBA; `only_paths_via_adapter: true` means that host has no other path to the device\n4. `paths fc-adapters --cluster <c>` → WWPNs to hand to the SAN team\n5. **If `complete` is false**: hosts in `hosts_not_read` were not read (the reason says `NoPermission` or the connection state). Name them as unknown — never report them as missing the device\n6. **If \"Scope required\"**: pass exactly one of `--cluster`, `--host` or `--datastore`; this tool does not read every host at once\n\n### Multi-Target Operations\n\nAll commands accept `--target <name>` to operate against a specific vCenter or ESXi host from your config:\n\n```bash\n# Default target (first in config.yaml)\nvmware-storage datastore list\n\n# Specific target\nvmware-storage datastore list --target prod-vcenter\nvmware-storage iscsi status esxi-lab --target lab-esxi\n```\n\n## Usage Mode\n\n| Scenario | Recommended | Why |\n|----------|:-----------:|-----|\n| Local/small models (Ollama, Qwen) | **CLI** | ~2K tokens vs ~8K for MCP |\n| Cloud models (Claude, GPT-4o) | Either | MCP gives structured JSON I/O |\n| Automated pipelines | **MCP** | Type-safe parameters, structured output |\n\n## MCP Tools (14 — 10 read, 4 write)\n\nAll MCP tools accept an optional `target` parameter to select which vCenter/ESXi to connect to. The 4 write tools take `confirm` (default false): without it they change nothing and return `blast_radius` — the host and adapters touched, and for `storage_iscsi_remove_target` the paths, devices and datastores behind the target. Show it to the user; pass `confirm: true` only after they decide. `dry_run` is a deprecated alias.\n\nThe four Datastore read tools return the family list envelope — `{items, returned, limit, total, truncated, hint}` — rather than a bare array. Read the rows from `items`; `truncated` says whether the listing is complete, so it never has to be guessed from the row count. All four enumerate their collection in full, so `total` is the real count and `truncated` is always `false`.\n\n| Category | Tool | Type | Description |\n|----------|------|:----:|-------------|\n| Datastore | `list_all_datastores` | Read | List datastores with capacity, usage %, VM count |\n| | `browse_datastore` | Read | Browse files with optional path and glob pattern |\n| | `scan_datastore_images` | Read | Find OVA/ISO/OVF/VMDK in a datastore |\n| | `list_cached_images` | Read | Query local image registry with type/datastore filters |\n| iSCSI | `storage_iscsi_status` | Read | Show adapter status, HBA device, IQN, send targets |\n| | `storage_iscsi_enable` | Write | Enable software iSCSI adapter on a host |\n| | `storage_iscsi_add_target` | Write | Add iSCSI send target (IP + port) and rescan |\n| | `storage_iscsi_remove_target` | Write | Remove iSCSI send target and rescan |\n| | `storage_rescan` | Write | Rescan all HBAs and VMFS volumes |\n| vSAN | `vsan_health` | Read | Cluster health summary and disk group details |\n| | `vsan_capacity` | Read | Total/used/free capacity in GB and usage % |\n| | `vsan_efficiency` | Read | Dedup + compression status (vSAN Management SDK) |\n| FC / multipath | `fc_adapter_list` | Read | FC/FCoE HBAs per host: WWPN/WWNN, port type, status, reported speed |\n| | `storage_device_paths` | Read | Per-device path state across a cluster/host/datastore; visibility and path-count differences |\n\n**Read/write split**: 10 tools are read-only, 4 modify state. Write tools require explicit parameters (host name, IP address), preview unless `confirm: true`, refuse when a datastore would lose every path or the host's storage view cannot be read, and are audit-logged. `storage_iscsi_remove_target` is classified `risk:high` (destructive — LUNs can become inaccessible) and goes through the policy confirmation gate.\n\nRunning with local or small models? See [`references/agent-guardrails.md`](references/agent-guardrails.md).\n\n## CLI Quick Reference\n\n```bash\n# Datastore\nvmware-storage datastore list [--target <name>]\nvmware-storage datastore browse <ds_name> [--path <subdir>] [--pattern \"*.ova\"]\nvmware-storage datastore scan-images <ds_name> [--target <name>]\n\n# iSCSI\nvmware-storage iscsi enable <host> [--dry-run]\nvmware-storage iscsi status <host>\nvmware-storage iscsi add-target <host> <ip> [--port 3260] [--dry-run]\nvmware-storage iscsi remove-target <host> <ip> [--port 3260] [--dry-run]\nvmware-storage iscsi rescan <host> [--dry-run]\n\n# vSAN\nvmware-storage vsan health <cluster> [--target <name>]\nvmware-storage vsan capacity <cluster> [--target <name>]\n\n# Fibre Channel / multipath (read-only)\nvmware-storage paths fc-adapters [--cluster <c> | --host <h>]\nvmware-storage paths devices (--cluster <c> | --host <h> | --datastore <ds>) [--device <naa>] [--adapter <vmhba>] [--only-differences]\n\n# Diagnostics\nvmware-storage doctor [--skip-auth]\n```\n\n> Full CLI reference with all options and output formats: see `references/cli-reference.md`\n\n## Troubleshooting\n\n### iSCSI enable fails with \"already enabled\"\n\nNot an error. The software iSCSI adapter is already active on that host. The response includes the current HBA device name and IQN. Run `iscsi status` to see configured send targets.\n\n### \"Datastore not found\" when browsing\n\nDatastore names are **case-sensitive**. Run `vmware-storage datastore list` to get the exact name. Common mistakes: `Datastore1` vs `datastore1`, trailing spaces.\n\n### `vsan_health` returns `overall_health: null`\n\n`null` means the health service was **not asked**, and `health_not_queried_reason` says why. It is deliberately not the string `\"unknown\"` — vSAN returns that itself, so using it for \"we did not ask\" made the two impossible to tell apart (on one VCF 9.1 cluster it stood in for `red`). A string in `overall_health` is always vSAN's own answer.\n\nThe usual cause is a **standalone ESXi** target: `VsanVcClusterHealthSystem` runs in vCenter's vSAN Health Service, so connect to the vCenter that manages the cluster. Otherwise read it in the vCenter UI under Cluster > Monitor > vSAN > Skyline Health.\n\n`health_checked_at` is the age of vCenter's cached summary. This tool reads that cache — the same one Skyline Health shows — rather than triggering a full health run, which takes minutes and loads the cluster.\n\n### Rescan doesn't discover new LUNs\n\nAfter adding iSCSI targets, the storage subsystem may need 10-30 seconds to enumerate new LUNs. Steps to resolve:\n1. Verify the target IP is reachable from the ESXi host (`vmkping` from ESXi shell)\n2. Check that the iSCSI target is correctly configured: `vmware-storage iscsi status <host>`\n3. Wait 15-30 seconds, then rescan again: `vmware-storage iscsi rescan <host>`\n\n### \"Password not found\" error\n\nThe password environment variable is missing. Variable names follow the pattern `VMWARE_<TARGET_NAME_UPPER>_PASSWORD` where hyphens become underscores. Example: target `my-vcenter` needs `VMWARE_MY_VCENTER_PASSWORD`. Check your `~/.vmware-storage/.env` file.\n\n### Doctor reports \".env permissions too open\"\n\nThe `.env` file contains passwords and must have owner-only permissions:\n\n```bash\nchmod 600 ~/.vmware-storage/.env\n```\n\n### Connection timeout to vCenter\n\nThe `doctor` command tests connectivity with a 5-second TCP timeout. If your vCenter is on a high-latency network, the check may fail even though the connection works. Use `--skip-auth` to bypass both connectivity and auth checks, then test manually.\n\n### `invalid peer certificate: UnknownIssuer` when starting MCP via uvx\n\nCorporate TLS proxies inject certificates that uv's bundled CA store doesn't trust. Use the recommended `vmware-storage mcp` form (no PyPI re-resolve), or set `export UV_NATIVE_TLS=true` to make uv use system CAs.\n\n## Safety\n\n- **No VM operations**: This skill cannot power on/off, create, delete, or modify VMs — that scope belongs to `vmware-aiops`\n- **Read-heavy**: 10 of 14 tools are read-only (list, browse, scan, cached images, status, health, capacity, efficiency, FC adapters, device paths)\n- **Audit logging**: All operations (including reads) are logged to `~/.vmware/audit.db` (SQLite WAL, via vmware-policy) with timestamp, user, target, operation, parameters, and result\n- **Double confirmation**: CLI write commands (iSCSI enable, add/remove target) require two separate \"Are you sure?\" prompts before executing\n- **Dry-run mode**: All write commands support `--dry-run` to preview API calls without executing\n- **Input validation**: IP addresses validated via `ipaddress.ip_address()`, ports checked for 1-65535 range, host/cluster/datastore names looked up before operations\n- **Prompt injection defense**: Datastore file names and paths from vSphere are sanitized via `_sanitize()` — strips control characters (C0/C1), truncates to 500 chars — preventing malicious file names from injecting instructions into downstream LLM agents\n- **Credential safety**: Passwords loaded only from environment variables (`.env` file), never from `config.yaml`; `.env` permissions are checked at startup\n- **L5 auto-remediation patterns (PoC)**: The [`patterns/`](../../patterns/) directory hosts L5 auto-remediation **candidate** patterns under the Enterprise Harness Engineering framework. First PoC: [`patterns/iscsi-target-stale-rescan.yaml`](../../patterns/iscsi-target-stale-rescan.yaml) — iSCSI HBA rescan classified as `risk:low` + `reversible:true` + `repeatable:true`. Schema only; **not yet enforced by the runtime**. See `references/capabilities.md` § Automation Level Reference for the full L1–L5 table.\n\n> Full security details: see `references/setup-guide.md`\n\n## Setup\n\n```bash\nuv tool install vmware-storage==1.11.0\nmkdir -p ~/.vmware-storage\ncp config.example.yaml ~/.vmware-storage/config.yaml\n# Edit config.yaml with your vCenter/ESXi targets\n\n# Add to ~/.vmware-storage/.env (create if missing, chmod 600):\n# VMWARE_MY_VCENTER_PASSWORD=<your-password>\nchmod 600 ~/.vmware-storage/.env\n\nvmware-storage doctor\n```\n\n> All tools are automatically audited via vmware-policy. Audit logs: `vmware-audit log --last 20`\n\n> Full setup guide with multi-target config, MCP server setup, and Docker: see `references/setup-guide.md`\n\n## Architecture\n\n```\nUser (natural language)\n  ↓\nAI Agent (Claude Code / Goose / Cursor)\n  ↓ reads SKILL.md\nvmware-storage CLI or MCP server (stdio transport)\n  ↓ pyVmomi (vSphere SOAP API)\nvCenter Server / ESXi\n  ↓\nDatastores / iSCSI / vSAN\n```\n\nThe MCP server uses stdio transport (local only, no network listener). Connections to vSphere use SSL/TLS on port 443.\n\n## Audit & Safety\n\nAll operations are automatically audited via vmware-policy (`@vmware_tool` decorator):\n- Every tool call logged to `~/.vmware/audit.db` (SQLite, framework-agnostic)\n- Policy rules enforced via `~/.vmware/rules.yaml` (deny rules, maintenance windows, risk levels)\n- Risk classification: each tool tagged as low/medium/high/critical\n- View recent operations: `vmware-audit log --last 20`\n- View denied operations: `vmware-audit log --status denied`\n\nvmware-policy is automatically installed as a dependency — no manual setup needed.\n\n## License\n\nMIT — [github.com/vmware-skills/VMware-Storage](https://github.com/vmware-skills/VMware-Storage)\n\nFile v1.11.0:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"vmware-storage\",\n  \"version\": \"1.11.0\",\n  \"publishedAt\": 1789790157912\n}\n\nFile v1.11.0:references/agent-guardrails.md\n\n# Operating vmware-storage with a local / small model\n\nClaude-class models drive this skill without special instruction. Smaller and\nlocally-hosted models — Llama 3.3 70B, Qwen, Mistral, and similar, served\nthrough Goose, Ollama, or OpenShift AI — need explicit operating rules to call\ntools reliably.\n\nThis page exists because an operator wrote those rules by hand first. The\nguardrails below are adapted, with thanks, from the working configuration\n[@juanpf-ha](https://github.com/juanpf-ha) developed while running\nvmware-monitor and vmware-aria against a production vSphere estate with Llama\n3.3 70B FP8 on an on-prem H100\n([VMware-AIops#31](https://github.com/vmware-skills/VMware-AIops/issues/31)). The\ncross-skill rules are identical across this family; the parts below marked\nvmware-storage are specific to this skill.\n\nvmware-storage exposes 14 MCP tools, 4 of which change state. The write\nsurface is small but sharp: removing an iSCSI send target can make LUNs — and\nevery VM living on them — inaccessible.\n\n> **Disclaimer**: This is a community-maintained open-source project and is\n> **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom\n> Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom.\n\n---\n\n## First: the rules you no longer need to write\n\nSeveral guardrails from the original configuration are now enforced by the\nskill itself. Prompt instructions are advisory — a model can ignore them.\nThese are structural, so it cannot.\n\n| Guardrail you would otherwise prompt for | Now enforced by |\n|---|---|\n| \"Preview the change before applying it\" | **`confirm` defaults to false.** A call to any of the 4 write tools without `confirm: true` changes nothing and returns `blast_radius`. Previewing is the default path, not a convention the model has to remember to honour. |\n| \"Don't cut off storage that is in use\" | **Refusal.** `storage_iscsi_remove_target` with `confirm: true` is refused when a datastore would lose every path, or when any path or static target behind the send target cannot be attributed. |\n| \"Use explicit limits for queries that may return large amounts of data\" | **The list envelope.** The four datastore read tools return `{items, returned, limit, total, truncated, hint}`, so the model reads truncation instead of guessing at it. All four enumerate their collection in full, so `total` is the real count and `truncated` is always `false`. |\n| \"If a listing came back empty, say so rather than claiming the call failed\" | Same envelope. Empty `items` with `truncated: false` means checked-and-none — a stated result, not a silence the model has to interpret. |\n| \"Log every state change you make\" | **The `@vmware_tool` decorator.** Every operation is recorded to `~/.vmware/audit.db` before the model sees the result, and policy rules are evaluated ahead of execution. `storage_iscsi_remove_target` is classified `risk:high` and goes through the policy confirmation gate. |\n\n---\n\n## The system prompt\n\nEverything below still benefits from being stated explicitly. Copy this into\nyour agent's instruction block.\n\n```text\n## Tool use\n\n- Always call an MCP tool before answering any question about the current\n  VMware environment. Never answer from memory or assumption.\n- Never describe a tool call, and never output a JSON example, instead of\n  executing the tool. If you intend to call a tool, call it.\n- If a tool fails, report the actual error text. Do not complete the answer\n  with assumptions about what the result would have been.\n- Use explicit limits on queries that may return large amounts of data. Do not\n  request unlimited results unless the user asks for them.\n- Datastore and host names are case-sensitive. Resolve the exact name with a\n  list tool before using it; do not correct or reformat what the user typed.\n\n## Skill routing\n\n- vmware-storage: datastores, datastore browsing, image scanning, iSCSI\n  adapters and send targets, vSAN health and capacity, and read-only Fibre\n  Channel HBA inventory and multipath path state.\n- vmware-monitor: read-only vCenter inventory, hosts, alarms, events,\n  performance. Prefer it for any question that only reads.\n- vmware-aiops: VM lifecycle. This skill cannot power, create, delete or\n  reconfigure a VM — route those there.\n- vmware-vks: Supervisor storage policies and namespace storage usage.\n- vmware-aria: capacity forecasting and trend analysis.\n- vmware-pilot: multi-step workflows that need approval gates.\n\n## Data fidelity\n\n- Never invent datastores, hosts, LUNs, targets, or capacity figures. If a tool\n  did not return it, it does not exist for this answer.\n- Preserve the exact status, health-state and accessibility values the tools\n  return. Do not translate, normalise, or prettify enum values.\n- Report capacity in the units the tool returned. Do not convert GB to TB or\n  recompute a usage percentage yourself.\n- If a requested field was not returned, show it as \"not available\". Do not\n  infer it from other fields.\n- Preserve the original order and the full set of fields when the user asks\n  for specific ones.\n- When a response is long, report every item it contains. If a result is\n  truncated, the tool says so explicitly — report the truncation rather than\n  describing the visible subset as the whole.\n\n## Analysis discipline\n\n- Separate observed data from interpretation. State which is which.\n- Do not claim a capacity, performance, or configuration problem unless the\n  tool output contains explicit supporting evidence. A datastore at 80% is a\n  number, not an incident.\n- Avoid generic recommendations that are not directly supported by the results.\n\n## Writes in vmware-storage\n\n- Call any iSCSI or rescan tool without confirm first, show the user the\n  returned blast_radius, and pass confirm: true only after they decide.\n- storage_iscsi_remove_target is destructive: LUNs behind that target can become\n  inaccessible, taking their VMs with them. Say so before proposing it.\n- \"Already enabled\" from storage_iscsi_enable is not an error. Report the\n  returned HBA device and IQN.\n- After adding a target, the storage subsystem needs 10-30 seconds before new\n  LUNs appear. An empty rescan result is not proof the target is wrong.\n```\n\n---\n\n## Known failure modes on small models\n\nObserved with Llama 3.3 70B FP8 (Goose, on-prem H100), and useful as a\nchecklist when evaluating any local model against these skills:\n\n| Symptom | Mitigation |\n|---|---|\n| Describes a tool call, or emits a JSON example, instead of executing it | The \"never describe a tool call\" rule above. Also check your harness is not echoing tool schemas into context — models imitate the nearest format they see. |\n| Long tool responses: omits items, or reports \"no data returned\" when data was present | Ask for explicit limits so responses stay small. Check the envelope's `truncated` / `returned` / `total` fields rather than trusting the model's summary — a \"no data\" claim is checkable against `returned`. |\n| Adds generic recommendations unsupported by results | The \"analysis discipline\" rules. Capacity output invites invented advice more than most — hold it to the evidence. |\n| Drops requested fields or reorders results | State the required fields and ordering in the request itself, not only in the system prompt. |\n| Multi-tool workflows take 30–50s end to end | Prefer the tools that answer in one call: `list_all_datastores` already carries capacity, usage % and VM count, and `vsan_health` covers cluster health and disk groups together. Neither needs a per-object follow-up loop. |\n| Silently corrects a datastore name's case and reports on the wrong object | Resolve names through `list_all_datastores` first, and have the model echo the resolved name before acting. |\n| Recomputes usage percentages and gets them wrong | The \"report capacity in the units the tool returned\" rule. |\n| Treats \"already enabled\" as a failure and retries | It is a stated result. The response carries the HBA device and IQN. |\n| Reports a host as \"missing the LUN\" when that host was never read | `storage_device_paths` lists such hosts in `hosts_not_read` and sets `complete: false`; they are never in `not_seen_on`, and neither is any disk that lives inside one host. Require the model to name unread hosts as unknown. |\n| Calls a `standby` path a failure | Only `states_needing_attention` (dead/disabled) is a finding. `standby` is normal on active/passive arrays. |\n\n## Reporting results\n\nLocal-model compatibility is an explicit design constraint for this family, and\nthe evidence base is small. If you evaluate a model against this skill —\nQwen, Mistral, Granite, or anything else — a report of what worked and what did\nnot is genuinely useful:\n[github.com/vmware-skills/VMware-Storage/issues](https://github.com/vmware-skills/VMware-Storage/issues).\n\nFile v1.11.0:references/capabilities.md\n\n# VMware Storage Capabilities\n\nAll 11 MCP tools exposed by `vmware-storage-mcp`, organized by category.\n\n## Automation Level Reference\n\nEach operation is classified by autonomy level per the Enterprise Harness Engineering framework:\n\n| Level | Meaning | Agent autonomy | Examples in this skill |\n|:-:|---|---|---|\n| **L1** | Read-only, raw data | Always auto-run | `list_all_datastores`, `browse_datastore`, `scan_datastore_images`, `list_cached_images`, `storage_iscsi_status`, vSAN status queries |\n| **L2** | Read + analysis / recommendation | Always auto-run | datastore capacity analysis, image registry queries, iSCSI target health correlation |\n| **L3** | Single write — user must approve | Only after explicit confirmation; high-risk ops require double-confirm + `--dry-run` (see Confirm column) | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target`, vSAN cluster ops |\n| **L4** | Multi-step plan / apply workflow | Plan generation auto; apply gated by user approval | *(roadmap — multi-host iSCSI rollout, vSAN expansion plans)* |\n| **L5** | Auto-remediation from learned pattern | Pattern library only; requires `risk:low` + `reversible:true` + `repeatable:true` + signed approval | **PoC pattern (v1.5.16+)**: [`patterns/iscsi-target-stale-rescan.yaml`](../../../patterns/iscsi-target-stale-rescan.yaml) — scans for stale iSCSI devices (`devices_inaccessible_count > 0`, missing expected devices, or `last_rescan_age_minutes > 60`); action: invoke `storage_rescan` on the affected `(host, target)`; classified low-risk because the rescan is idempotent and non-destructive (no data, config, or VM state is modified). Schema only — **not yet enforced by the runtime**. |\n\n**Notes**:\n- L1/L2 tools are always safe for agents to call without confirmation.\n- L3 tools always pass through the `@vmware_tool` decorator: connection check → policy check → audit log → double-confirm.\n- L5 PoC pattern (`patterns/iscsi-target-stale-rescan.yaml`, v1.5.16+) is a **reference design**: it documents the candidate trigger / action / validation / circuit-breaker shape under `schema_version: 1` (see [vmware-policy auto-remediation pattern docs](https://github.com/vmware-skills/VMware-Policy/blob/main/docs/auto-remediation-patterns.md)). The pattern is `approval.status: poc_unsigned` and will only become live after `success_count_required: 5` + `failure_count_max: 0` + `distinct_operators_required: 2` + `days_observed: 90` are met and the pattern is signed.\n\n## Datastore (4 tools)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `list_all_datastores` | List datastores with capacity, usage %, VM count | `target` (string, optional) | Low | No |\n| `browse_datastore` | Browse files with optional path and glob pattern | `datastore` (string, **required**), `path` (string, optional), `pattern` (string, optional), `target` (string, optional) | Low | No |\n| `scan_datastore_images` | Find OVA/ISO/OVF/VMDK deployable images in a datastore | `datastore` (string, **required**), `target` (string, optional) | Low | No |\n| `list_cached_images` | Query local image registry with type/datastore filters | `image_type` (string, optional), `datastore` (string, optional) | Low | No |\n\n**List envelope**: all four return `{items, returned, limit, total, truncated, hint}` instead of a bare array, so an agent can tell a complete answer from a first page rather than inferring it (VMware-AIops issue #31). Each enumerates its collection in full — a PropertyCollector walk, a datastore browse task, or the on-disk registry — so `total` is the real count and `truncated` is always `false`. On error the tools return `{error, hint}` (a dict, not a one-element list).\n\n## iSCSI (5 tools)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `storage_iscsi_status` | Show adapter status, HBA device, IQN, configured send targets | `host` (string, **required**), `target` (string, optional) | Low | No |\n| `storage_iscsi_enable` | Enable software iSCSI adapter on a host | `host` (string, **required**), `confirm` (boolean, default: false — previews), `target` (string, optional) | Medium | Yes |\n| `storage_iscsi_add_target` | Add iSCSI send target (IP + port) and rescan storage | `host` (string, **required**), `address` (string, **required**), `port` (integer, default: 3260), `confirm` (boolean, default: false — previews), `target` (string, optional) | Medium | Yes |\n| `storage_iscsi_remove_target` | Remove iSCSI send target and rescan storage | `host` (string, **required**), `address` (string, **required**), `port` (integer, default: 3260), `confirm` (boolean, default: false — previews), `target` (string, optional) | Medium | Yes |\n| `storage_rescan` | Rescan all HBAs and VMFS volumes on a host | `host` (string, **required**), `confirm` (boolean, default: false — previews), `target` (string, optional) | Low | Yes |\n\n## vSAN (3 tools)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `vsan_health` | Cluster health summary with disk group details per host | `cluster` (string, **required**), `target` (string, optional) | Low | No |\n| `vsan_capacity` | Total/used/free capacity in GB and usage percentage | `cluster` (string, **required**), `target` (string, optional) | Low | No |\n| `vsan_efficiency` | Dedup + compression status (vSAN Management SDK) | `cluster_name` (string, **required**), `target` (string, optional) | Low | No |\n\n## Fibre Channel / multipath (2 tools, read-only)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `fc_adapter_list` | FC and FCoE HBAs per host: vmhba, model, driver, status, port type, WWPN/WWNN, `speed_reported` | `cluster` or `host` (optional; neither = every host on the target), `limit` (1-200, default 50), `offset`, `target` | Low | No |\n| `storage_device_paths` | Per-device (NAA) SCSI multipath state across the hosts of one scope: `shared`, `seen_by`, `not_seen_on`, `path_count_differs`, `states_needing_attention`, per-host path counts by state, working paths, adapters, PSP/SATP, VMFS datastores | exactly one of `cluster` / `host` / `datastore` (**required**); `device`, `adapter`, `only_differences`, `limit`, `offset`, `target` | Low | No |\n\nSource: each host's `config.storageDevice` (HBAs, SCSI LUNs, `multipathInfo`) and `config.fileSystemVolume.mountInfo`, fetched in one PropertyCollector call per scope. No SSH, no array or switch credentials, no rescans. Requested in [VMware-Storage#18](https://github.com/vmware-skills/VMware-Storage/issues/18).\n\n- **Unread is not empty.** A host whose storage view could not be read — `NoPermission`, not connected (vCenter keeps a lost host's last-known config, so it is not treated as current), or missing from vCenter's reply — is listed in `hosts_not_read` with the reason, `complete` is `false`, and that host is never counted in `not_seen_on` or `hosts_without_fc`.\n- **Observed state, not verdicts.** `states_needing_attention` holds only `dead` and `disabled`. `standby` is reported in `by_state` but not flagged (it is normal on active/passive arrays), and a path count does not prove independent fabrics.\n- **Only shared devices can be missing.** `not_seen_on` is filled only when `shared` is true: the device is reached over FC or iSCSI (judged by the path's adapter type, so a dead path that lost its transport still counts) or already seen by more than one host. A local-marked device is exempt even on a SAN — that is how a boot-from-SAN LUN zoned to one host is usually marked. A disk inside one host — local, or a SAS/NVMe drive ESXi marks non-local — is never reported missing elsewhere. `mpx.*` names, non-disk LUNs (CD-ROM) and unresolved LUNs are per-host and never merged across hosts, since every host can have its own `mpx.vmhba0:C0:T0:L0`. A side effect: an array LUN that has no NAA identifier and is named `mpx.*` is shown once per host rather than as one shared device. Each path row carries `protocol` (`fc`, `iscsi` or null).\n- **`adapter`** matches by vmhba name; in a cluster scope `vmhba2` can be a different card on each host.\n- **`complete`** is false when any host was not read, or when a datastore's backing devices are unknown (no readable host reports the VMFS volume mounted).\n- **`speed_reported`** is the raw vSphere value. The API documents bits per second, but hosts commonly report Gbit/s (e.g. `16`), so it is not converted.\n- **Scope**: `storage_device_paths` requires one scope and refuses to read every host at once — multipath data is large on estates with hundreds of hosts. Per-path detail is returned only when `device` or `datastore` is given.\n- **Not covered**: NVMe-oF namespaces may not appear (they are not in `multipathInfo`); zoning, array masking and switch health are out of scope.\n- **Privileges**: reads host configuration only. Expected to work with the Read-Only role; not yet validated against a restricted account.\n- **Typical response**: `fc_adapter_list` ~80 tokens per adapter; `storage_device_paths` ~120 tokens per device per host in summary form, 2–3× that with per-path detail.\n\n## Risk Level Definitions\n\n| Level | Meaning | Examples |\n|-------|---------|---------|\n| **Low** | Read-only query, no state change | `list_all_datastores`, `browse_datastore`, `vsan_health`, `storage_iscsi_status`, `storage_rescan` |\n| **Medium** | State change affecting storage configuration, but recoverable | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target` |\n\n## Tool Counts by Risk Level\n\n| Risk | Count | Tools |\n|------|:-----:|-------|\n| Low | 11 | All read-only tools + `storage_rescan` |\n| Medium | 3 | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target` |\n\n> Note: `storage_rescan` triggers a host-level HBA rescan which is non-destructive (discovery only) and classified as Low risk. The iSCSI write tools (`enable`, `add_target`, `remove_target`) are Medium risk because they modify the host's iSCSI configuration, but changes are reversible.\n\n## Input Validation\n\n| Parameter | Validation | Error on Invalid |\n|-----------|-----------|-----------------|\n| `address` (IP) | `ipaddress.ip_address()` — accepts IPv4 and IPv6 | `ISCSIError: Invalid IP address` |\n| `port` | Integer in range 1-65535 | `ISCSIError: Port must be 1-65535` |\n| `host` | Looked up by exact name match in vSphere inventory | `HostNotFoundError` |\n| `cluster` | Looked up by exact name match in vSphere inventory | `VSANError: Cluster not found` |\n| `datastore` | Looked up by exact name match (case-sensitive) | `Datastore not found` |\n\n## Audit Coverage\n\nAll 14 tools are wrapped with `@vmware_tool` from vmware-policy, which provides:\n\n- **Pre-execution**: Policy rule check against `~/.vmware/rules.yaml` (deny rules, maintenance windows)\n- **Post-execution**: Audit log entry written to `~/.vmware/audit.db` (SQLite WAL mode)\n- **Input sanitization**: All vSphere API response text processed through `sanitize()` (truncation + control character cleanup)\n\n## Read/Write Split\n\n| Type | Count | Tools |\n|------|:-----:|-------|\n| Read | 10 | `list_all_datastores`, `browse_datastore`, `scan_datastore_images`, `list_cached_images`, `storage_iscsi_status`, `vsan_health`, `vsan_capacity`, `vsan_efficiency`, `fc_adapter_list`, `storage_device_paths` |\n| Write | 4 | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target`, `storage_rescan` |\n\n> Write tools require explicit parameters (host name, IP address) and support `--dry-run` in CLI mode. Over MCP they preview by default: without `confirm: true` they return `blast_radius` and change nothing. All write operations are audit-logged with timestamp, user, target, operation, parameters, and result.\n\n## Connection Requirements\n\n| Requirement | Datastore Tools | iSCSI Tools | vSAN Tools |\n|-------------|:---------------:|:-----------:|:----------:|\n| vCenter connection | Required | Not required (direct ESXi OK) | Required |\n| ESXi host access | Via vCenter | Direct or via vCenter | Via vCenter |\n| pyVmomi | Required | Required | Required |\n| vSAN SDK | Not required | Not required | Recommended (for full health) |\n\n## Runtime Requirements\n\n| Requirement | Minimum | Notes |\n|-------------|---------|-------|\n| Python | 3.10+ | Lowered from 3.11 in v1.5.27 for Goose sandbox / Ubuntu 22.04 compatibility. Tested on 3.10 / 3.11 / 3.12. |\n| OS | macOS, Linux | stdio MCP transport — no network listener required |\n\nFile v1.11.0:references/cli-reference.md\n\n# CLI Reference\n\nComplete command reference for `vmware-storage` CLI.\n\n## Global Options\n\nAll commands accept these options:\n\n| Option | Description |\n|--------|-------------|\n| `--target <name>` | Target name from `~/.vmware-storage/config.yaml` (defaults to first target) |\n| `--config <path>` | Override config file path |\n| `--help` | Show command help |\n\n## Datastore Commands\n\n### `datastore list`\n\nList all datastores with capacity, usage, and VM count.\n\n```bash\nvmware-storage datastore list\nvmware-storage datastore list --target my-vcenter\n```\n\nOutput columns: Name, Type, Total GB, Free GB, Usage %, VMs.\nUsage above 85% is highlighted in red.\n\n### `datastore browse`\n\nBrowse files in a datastore directory. Supports glob pattern filtering.\n\n```bash\n# Browse root of a datastore\nvmware-storage datastore browse datastore01\n\n# Browse a subdirectory\nvmware-storage datastore browse datastore01 --path \"iso-images\"\n\n# Filter by pattern\nvmware-storage datastore browse datastore01 --pattern \"*.ova\"\nvmware-storage datastore browse datastore01 --path \"templates\" --pattern \"*.iso\"\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `ds_name` | Yes | - | Datastore name (case-sensitive) |\n| `--path` | No | `\"\"` (root) | Subdirectory path within the datastore |\n| `--pattern` | No | `\"*\"` | Glob pattern to filter files |\n\nOutput: JSON array of file objects with `name`, `size_mb`, `type`, `modified`, `ds_path`.\n\n### `datastore scan-images`\n\nScan a datastore for deployable images (OVA, ISO, OVF, VMDK).\n\n```bash\nvmware-storage datastore scan-images datastore01\nvmware-storage datastore scan-images datastore01 --target prod-vcenter\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `ds_name` | Yes | - | Datastore name |\n\nScans for patterns: `*.ova`, `*.ovf`, `*.iso`, `*.vmdk`. Results are sorted by name.\n\n## iSCSI Commands\n\n### `iscsi enable`\n\nEnable the software iSCSI adapter on an ESXi host.\n\n```bash\nvmware-storage iscsi enable esxi-01\nvmware-storage iscsi enable esxi-01 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\n**Safety**: Requires double confirmation (two prompts). If the adapter is already enabled, returns current HBA device and IQN without making changes.\n\n### `iscsi status`\n\nShow iSCSI adapter status and configured send targets.\n\n```bash\nvmware-storage iscsi status esxi-01\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n\nOutput: JSON with `enabled`, `hba_device`, `iqn`, and `send_targets` (list of address/port pairs).\n\n### `iscsi add-target`\n\nAdd an iSCSI send target to a host and automatically rescan storage.\n\n```bash\nvmware-storage iscsi add-target esxi-01 192.168.1.100\nvmware-storage iscsi add-target esxi-01 10.0.0.50 --port 3261\nvmware-storage iscsi add-target esxi-01 192.168.1.100 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `address` | Yes | - | iSCSI target IP address (validated) |\n| `--port` | No | `3260` | iSCSI target port (1-65535) |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\n**Safety**: Requires double confirmation. IP address and port are validated before any API call. If the target is already configured, returns without making changes. After adding, automatically rescans all HBAs and VMFS volumes.\n\n### `iscsi remove-target`\n\nRemove an iSCSI send target from a host and automatically rescan storage.\n\n```bash\nvmware-storage iscsi remove-target esxi-01 192.168.1.100\nvmware-storage iscsi remove-target esxi-01 10.0.0.50 --port 3261\nvmware-storage iscsi remove-target esxi-01 192.168.1.100 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `address` | Yes | - | iSCSI target IP address |\n| `--port` | No | `3260` | iSCSI target port |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\n**Safety**: Requires double confirmation. Raises an error if the target is not found (prevents accidental no-ops). Automatically rescans after removal.\n\n### `iscsi rescan`\n\nRescan all HBAs and VMFS volumes on an ESXi host.\n\n```bash\nvmware-storage iscsi rescan esxi-01\nvmware-storage iscsi rescan esxi-01 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\nCalls both `RescanAllHba()` and `RescanVmfs()` on the host storage system.\n\n## vSAN Commands\n\n### `vsan health`\n\nGet vSAN cluster health summary including disk group details.\n\n```bash\nvmware-storage vsan health Cluster-Prod\nvmware-storage vsan health Cluster-Prod --target my-vcenter\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `cluster_name` | Yes | - | Name of the vSAN-enabled cluster |\n\nOutput: JSON with `vsan_enabled`, `overall_health`, `host_count`, `disk_groups` (per-host cache/capacity disk info).\n\n### `vsan capacity`\n\nGet vSAN capacity overview (total/used/free) for a cluster.\n\n```bash\nvmware-storage vsan capacity Cluster-Prod\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `cluster_name` | Yes | - | Name of the vSAN-enabled cluster |\n\nOutput: JSON with `total_gb`, `used_gb`, `free_gb`, `usage_pct`, `datastore_name`.\n\n## Fibre Channel / Multipath Commands (read-only)\n\n### `paths fc-adapters`\n\nList FC and FCoE HBAs per host with WWPN/WWNN, port type, status and the raw reported speed.\n\n```bash\nvmware-storage paths fc-adapters --cluster Cluster-Prod\nvmware-storage paths fc-adapters --host esxi-01.example.com\nvmware-storage paths fc-adapters            # every host on the target\n```\n\n| Option | Required | Default | Description |\n|--------|:--------:|---------|-------------|\n| `--cluster` | No | - | Cluster name |\n| `--host` | No | - | ESXi host name |\n| `--limit` / `--offset` | No | 50 / 0 | Paging (limit 1-200) |\n\nOutput: list envelope plus `hosts_without_fc` and `hosts_not_read` (hosts that were not read are never reported as having no FC HBA).\n\n### `paths devices`\n\nPer-device SCSI multipath state across the hosts of one scope.\n\n```bash\nvmware-storage paths devices --datastore ds-fc-01                     # dead/disabled paths behind a datastore\nvmware-storage paths devices --cluster Cluster-Prod --only-differences # path counts differ, or a shared device is missing\nvmware-storage paths devices --cluster Cluster-Prod --device naa.60060e80123456\nvmware-storage paths devices --host esxi-01 --adapter vmhba2          # what depends on one HBA\n```\n\n| Option | Required | Default | Description |\n|--------|:--------:|---------|-------------|\n| `--cluster` / `--host` / `--datastore` | Exactly one | - | Scope |\n| `--device` | No | - | Canonical name (`naa.…`) or display name, case-insensitive |\n| `--adapter` | No | - | vmhba name; adds `paths_via_adapter` and `only_paths_via_adapter` per host. Matched by name: in a cluster scope `vmhba2` can be a different card on each host |\n| `--only-differences` | No | false | Only devices whose visibility or path count differs across the hosts read |\n| `--limit` / `--offset` | No | 50 / 0 | Paging over devices (limit 1-200) |\n\nOutput: list envelope of devices (those with dead/disabled paths first), plus `summary`, `hosts_read`, `hosts_not_read`, `complete`, `scope_note` and `note`. Path states are reported as vSphere reports them; `standby` is not flagged.\n\n## Diagnostics\n\n### `doctor`\n\nRun environment and connectivity diagnostics.\n\n```bash\nvmware-storage doctor\nvmware-storage doctor --skip-auth\n```\n\n| Option | Description |\n|--------|-------------|\n| `--skip-auth` | Skip the vSphere authentication check (useful when vCenter is unreachable) |\n\nChecks performed:\n1. Config file exists (`~/.vmware-storage/config.yaml`)\n2. `.env` file exists with correct permissions (600)\n3. Targets are configured in config\n4. Network connectivity to all targets (TCP port check with 5s timeout)\n5. vSphere authentication (actual login via pyVmomi)\n6. MCP server module loads successfully\n\n## Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| `0` | Success |\n| `1` | Operation failed or doctor check failed |\n\n## Environment Variables\n\n| Variable | Description |\n|----------|-------------|\n| `VMWARE_STORAGE_CONFIG` | Override config file path (used by MCP server) |\n| `VMWARE_<TARGET>_PASSWORD` | Password for a target (e.g., `VMWARE_MY_VCENTER_PASSWORD`) |\n\nFile v1.11.0:references/setup-guide.md\n\n# Setup Guide\n\nComplete setup and security guide for `vmware-storage`.\n\n## Prerequisites\n\n- Python 3.10+\n- vCenter Server 6.7+ or standalone ESXi 6.7+\n- Network access to vCenter/ESXi on port 443 (or custom port)\n\n## Installation\n\n### Via uv (recommended)\n\n```bash\nuv tool install vmware-storage==1.11.0\n```\n\n### Via pip\n\n```bash\npip install vmware-storage==1.11.0\n```\n\n### From source\n\n```bash\ngit clone --branch v1.11.0 https://github.com/vmware-skills/VMware-Storage.git\ncd VMware-Storage\npip install -e .\n```\n\n## Configuration\n\n### 1. Create config directory\n\n```bash\nmkdir -p ~/.vmware-storage\n```\n\n### 2. Create config.yaml\n\n```bash\ncp config.example.yaml ~/.vmware-storage/config.yaml\n```\n\nEdit `~/.vmware-storage/config.yaml`:\n\n```yaml\ntargets:\n  - name: my-vcenter          # Target identifier (used in CLI --target flag)\n    host: vcenter.example.com  # Hostname or IP\n    username: administrator@vsphere.local\n    type: vcenter              # \"vcenter\" or \"esxi\"\n    port: 443\n    verify_ssl: false          # Set true if using valid certs\n    environment: production    # Which environment this target is — see below\n\n  - name: esxi-standalone\n    host: 10.0.0.50\n    username: root\n    type: esxi\n    port: 443\n    verify_ssl: false\n    environment: lab\n\nnotify:\n  webhook_url: \"\"              # Optional: webhook for notifications\n```\n\nThe first target in the list is the default (used when `--target` is not specified).\n\n#### `environment` — declare which environment each target is\n\n`environment:` is an optional free-form label. Policy scopes its rules by this\nvalue, so an environment-scoped `deny` rule in `~/.vmware/rules.yaml` can match\non it — for example, to freeze state-changing writes (`iscsi enable`,\n`iscsi add-target`, `iscsi remove-target`, `rescan`) on `production`. A target\nwith no label is simply not matched by such a rule.\n\nAny label works (`production`, `staging`, `lab`, or your own); the target's\n*name* is not used for scoping. Read-only operations are never affected. Run\n`vmware-audit policy` to see the rules actually in force.\n\n### 3. Create .env for credentials\n\nPasswords are **never stored in config.yaml**. They must be set as environment variables via the `.env` file.\n\n```bash\necho \"VMWARE_MY_VCENTER_PASSWORD=your_password\" > ~/.vmware-storage/.env\necho \"VMWARE_ESXI_STANDALONE_PASSWORD=root_password\" >> ~/.vmware-storage/.env\nchmod 600 ~/.vmware-storage/.env\n```\n\n**Naming convention**: `VMWARE_<TARGET_NAME_UPPER>_PASSWORD` where `<TARGET_NAME_UPPER>` is the target `name` from config.yaml, uppercased, with hyphens replaced by underscores.\n\nExamples:\n| Target name | Environment variable |\n|-------------|---------------------|\n| `my-vcenter` | `VMWARE_MY_VCENTER_PASSWORD` |\n| `esxi-standalone` | `VMWARE_ESXI_STANDALONE_PASSWORD` |\n| `prod01` | `VMWARE_PROD01_PASSWORD` |\n\n### 4. Verify setup\n\n```bash\nvmware-storage doctor\n```\n\nThis runs six checks: config file, .env file, targets, network connectivity, authentication, and MCP server module.\n\nUse `--skip-auth` if vCenter is temporarily unreachable:\n\n```bash\nvmware-storage doctor --skip-auth\n```\n\n## MCP Server Configuration\n\n### Claude Code / Claude Desktop\n\nAdd to your MCP config (`~/.claude.json` or Claude Desktop settings):\n\n```json\n{\n  \"mcpServers\": {\n    \"vmware-storage\": {\n      \"command\": \"vmware-storage\",\n      \"args\": [\"mcp\"],\n      \"env\": {\n        \"VMWARE_STORAGE_CONFIG\": \"~/.vmware-storage/config.yaml\"\n      }\n    }\n  }\n}\n```\n\n> v1.5.15+ recommends the single-command form `vmware-storage mcp`. Pre-1.5.15 used\n> `uvx --from vmware-storage vmware-storage-mcp`, which still works but re-resolves from <!-- install-pin: historical -->\n> PyPI on each launch and breaks behind corporate TLS proxies. The legacy\n> `vmware-storage-mcp` entry point is also kept for backward compatibility.\n\n### Goose\n\nAdd to `~/.config/goose/config.yaml`:\n\n```yaml\nextensions:\n  vmware-storage:\n    type: stdio\n    cmd: vmware-storage\n    args:\n      - mcp\n    env:\n      VMWARE_STORAGE_CONFIG: \"~/.vmware-storage/config.yaml\"\n```\n\n### Docker\n\n```bash\ndocker compose up -d\n```\n\nOr run manually:\n\n```bash\ndocker run -d \\\n  -v ~/.vmware-storage:/root/.vmware-storage:ro \\\n  -e VMWARE_STORAGE_CONFIG=/root/.vmware-storage/config.yaml \\\n  vmware-storage\n```\n\n### Password obfuscation at rest\n\nOn first load, any plaintext `*_PASSWORD` value in `.env` is automatically\nrewritten to a grep-safe `b64:<encoded>` form and decoded transparently at\nruntime, so a casual `grep` of the file no longer reveals the password. Values\nare read and written through python-dotenv's own parser, so the stored secret\nnever drifts from what you configured (quotes, inline comments, and trailing\nwhitespace are handled correctly).\n\n> **This is obfuscation, not encryption.** Anyone who can read the file can\n> still decode it. For real secrecy at rest, do not store the password in `.env`\n> at all — inject it from a secret manager (HashiCorp Vault, CyberArk, AWS\n> Secrets Manager, or a Kubernetes Secret) into the `*_PASSWORD` environment\n> variable at process start. The code reads the env var either way.\n\n## Security Details\n\n> **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom.\n\n### Credential Safety\n\n- Passwords are **only loaded from environment variables** (via `.env` file), never from `config.yaml`\n- The `.env` file permissions are checked at startup; a warning is logged if permissions are wider than `600` (owner read/write only)\n- The `doctor` command verifies `.env` permissions and reports failures\n\n### Audit Logging\n\nAll operations are logged to `~/.vmware/audit.db` (SQLite WAL mode, via vmware-policy).\n\nEach audit entry records:\n- **timestamp**: UTC ISO 8601\n- **target**: Which vCenter/ESXi was acted on\n- **operation**: What was done (e.g., `iscsi_enable`, `iscsi_add_target`, `query`)\n- **resource**: What resource was affected (host name, datastore name)\n- **parameters**: Full parameter set passed to the operation\n- **before_state / after_state**: State snapshots (when available)\n- **result**: Operation outcome\n- **user**: OS username who initiated the operation\n\nExample audit entry:\n\n```json\n{\n  \"timestamp\": \"2026-03-25T10:30:00+00:00\",\n  \"target\": \"my-vcenter\",\n  \"operation\": \"iscsi_add_target\",\n  \"resource\": \"esxi-01\",\n  \"parameters\": {\"host_name\": \"esxi-01\", \"address\": \"10.0.0.100\", \"port\": 3260},\n  \"before_state\": {},\n  \"after_state\": {},\n  \"result\": \"iSCSI target 10.0.0.100:3260 added to host 'esxi-01' and storage rescanned.\",\n  \"user\": \"admin\"\n}\n```\n\nRead-only operations (list, browse, scan, status, health, capacity) are also logged with `operation: \"query\"` for complete traceability.\n\n### Read-only access\n\nTo run the agent read-only, give it a read-only vCenter service account (RBAC) — enforced at the platform.\n\n### Double Confirmation on Destructive Operations\n\nCLI write commands require two separate confirmation prompts before executing:\n\n1. First prompt: \"Are you sure?\" (default: No)\n2. Second prompt: \"This modifies host storage configuration. Confirm again?\" (default: No)\n\nBoth must be answered `y` for the operation to proceed. This applies to:\n- `iscsi enable`\n- `iscsi add-target`\n- `iscsi remove-target`\n\n### Dry-Run Mode\n\nAll write commands support `--dry-run` to preview what would happen without making changes:\n\n```bash\nvmware-storage iscsi enable esxi-01 --dry-run\n# Output: [DRY-RUN] Would enable software iSCSI on host 'esxi-01'\n\nvmware-storage iscsi add-target esxi-01 10.0.0.100 --dry-run\n# Output: [DRY-RUN] Would add iSCSI target 10.0.0.100:3260 to host 'esxi-01' and rescan\n```\n\n### Prompt Injection Defense\n\nDatastore file names and paths returned from vSphere are sanitized before output via the `_sanitize()` function:\n\n- Strips C0/C1 control characters (U+0000-U+0008, U+000B, U+000C, U+000E-U+001F, U+007F-U+009F)\n- Preserves newlines and tabs\n- Truncates to 500 characters maximum\n\nThis prevents malicious file names on datastores from injecting prompts or instructions when the data flows to downstream LLM agents.\n\n### Input Validation\n\n- **IP addresses**: Validated via Python's `ipaddress.ip_address()` before any iSCSI operation\n- **Ports**: Validated to be in range 1-65535\n- **Datastore names**: Case-sensitive lookup; returns a clear error if not found\n- **Host names**: Looked up via vSphere inventory; raises `HostNotFoundError` if not found\n- **Cluster names**: Looked up via vSphere inventory; raises `VSANError` if not found\n\n### Transport Security\n\n- The MCP server uses **stdio transport** (local only) -- no network listener is opened\n- vSphere connections use SSL/TLS on port 443 by default\n- SSL certificate verification can be enabled per-target via `verify_ssl: true` in config.yaml\n\n### What This Skill Cannot Do\n\nThis skill has **no VM operations**. It cannot:\n- Power on, power off, or restart VMs\n- Create, clone, or delete VMs\n- Deploy OVA/OVF templates\n- Run commands inside guest VMs\n- Modify VM configuration (CPU, memory, network)\n\nFor VM operations, use `vmware-aiops`.\n\n## Multi-Target Setup\n\nYou can configure multiple vCenter/ESXi targets and switch between them:\n\n```yaml\ntargets:\n  - name: prod-vcenter\n    host: vcenter-prod.example.com\n    username: svc-storage@vsphere.local\n    type: vcenter\n\n  - name: dev-vcenter\n    host: vcenter-dev.example.com\n    username: administrator@vsphere.local\n    type: vcenter\n\n  - name: lab-esxi\n    host: 10.0.1.50\n    username: root\n    type: esxi\n```\n\n```bash\n# Uses first target (prod-vcenter) by default\nvmware-storage datastore list\n\n# Explicitly target dev\nvmware-storage datastore list --target dev-vcenter\n\n# Target standalone ESXi\nvmware-storage iscsi status lab-esxi --target lab-esxi\n```\n\n## Version Compatibility\n\n| vSphere / VCF | Support | Notes |\n|---------|---------|-------|\n| VCF 9.1 / vSphere 9.1 | Full | Released 2026-05-12. pyVmomi+vSAN SDK `<10.0` works via SOAP. |\n| VCF 9.0 / vSphere 9.0 | Full | pyVmomi 8.0.3+ with bundled vSAN SDK connects to vSphere 9. |\n| 8.0 | Full | vSAN SDK built into pyVmomi 8.0.3+ |\n| 7.0 | Full | All storage APIs work |\n| 6.7 | Compatible | iSCSI + datastore features work; vSAN limited |\n\n## File Locations\n\n| File | Purpose |\n|------|---------|\n| `~/.vmware-storage/config.yaml` | Connection targets and settings |\n| `~/.vmware-storage/.env` | Passwords (chmod 600) |\n| `~/.vmware/audit.db` | Operation audit trail (SQLite WAL, via vmware-policy) |\n| `~/.vmware-storage/image_registry.json` | Cached image scan results |\n| `~/.vmware-storage/scan.log` | Scanner log output |\n\nFile v1.11.0:skill-card.md\n\n## Description:\n\nvmware-storage helps agents manage VMware vSphere storage, including datastores, iSCSI targets, vSAN health and capacity, and Fibre Channel or multipath diagnostics.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, infrastructure engineers, and VMware operators use this skill to inspect datastore contents, scan deployable images, configure iSCSI storage, check vSAN health and capacity, and review Fibre Channel or multipath state from an agent workflow.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can receive powerful VMware storage-management access, including operations that affect iSCSI configuration and storage visibility.\n\nMitigation: Use least-privilege vCenter service accounts, avoid ESXi root where possible, and manually review every write preview before confirming.\n\nRisk: Setup guidance can lead to unsafe TLS or local password-file practices.\n\nMitigation: Use verify_ssl: true for production targets, trust the proper CA instead of disabling certificate checks, and replace local .env passwords with a secrets manager where possible.\n\nRisk: Removing or changing iSCSI targets can make LUNs and dependent VMs inaccessible.\n\nMitigation: Rely on preview-first write behavior, inspect the reported blast radius, and proceed with confirm=true only after explicit operator approval.\n\nRisk: Container-based installation can drift if an image is pulled without a stable reference.\n\nMitigation: Pin Docker images by tag or digest before deployment.\n\n## Reference(s):\n\n- [VMware Storage GitHub Repository](https://github.com/vmware-skills/VMware-Storage)\n- [ClawHub Skill Page](https://clawhub.ai/zw008/skills/vmware-storage)\n- [Setup Guide](references/setup-guide.md)\n- [CLI Reference](references/cli-reference.md)\n- [VMware Storage Capabilities](references/capabilities.md)\n- [Agent Guardrails](references/agent-guardrails.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline shell commands, configuration snippets, and operational guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Can also guide MCP tool calls that return structured VMware storage data and write previews.]\n\n## Skill Version(s):\n\n1.11.0 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.11.0:evals/evals.json\n\n{\n  \"skill_name\": \"vmware-storage\",\n  \"evals\": [\n    {\n      \"id\": 1,\n      \"prompt\": \"Add a new iSCSI target 10.0.1.50 on host esxi-01 and verify the new LUNs appear\",\n      \"expected_output\": \"iSCSI target added, storage rescanned, new datastores visible\",\n      \"files\": [],\n      \"expectations\": [\n        \"Uses storage_iscsi_enable if adapter not enabled\",\n        \"Uses storage_iscsi_add_target with correct IP\",\n        \"Uses storage_rescan or verifies with list_all_datastores\"\n      ]\n    },\n    {\n      \"id\": 2,\n      \"prompt\": \"Check vSAN health on cluster Production and show me the capacity breakdown\",\n      \"expected_output\": \"vSAN health status and capacity details\",\n      \"files\": [],\n      \"expectations\": [\n        \"Uses vsan_health for health summary\",\n        \"Uses vsan_capacity for capacity breakdown\",\n        \"Shows total/used/free in human-readable format\"\n      ]\n    },\n    {\n      \"id\": 3,\n      \"prompt\": \"Find all OVA files on datastore1 that I can use for deployment\",\n      \"expected_output\": \"List of deployable OVA images\",\n      \"files\": [],\n      \"expectations\": [\n        \"Uses scan_datastore_images or browse_datastore with OVA filter\",\n        \"Returns file paths suitable for deploy_vm_from_ova\"\n      ]\n    }\n  ]\n}\n\nArchive v1.10.0: 8 files, 27383 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (8508b), references/capabilities.md (12309b), references/cli-reference.md (8998b), references/setup-guide.md (10641b), skill-card.md (2269b), SKILL.md (19905b), _meta.json (134b)\n\nFile v1.10.0:SKILL.md\n\n---\nname: vmware-storage\ndescription: >\n  Use this skill whenever the user needs to manage VMware storage — datastores, iSCSI targets, and vSAN clusters.\n  Directly handles: browse datastores, scan for deployable images (OVA/ISO), configure iSCSI adapters and targets, check vSAN health and capacity, read-only Fibre Channel HBA/WWPN inventory and multipath path state.\n  Always use this skill for \"list datastores\", \"add iSCSI target\", \"check vSAN health\", \"browse datastore files\", \"scan for OVA images\", \"dead paths\", \"FC HBA WWPN\", or any storage-related VMware task.\n  Do NOT use for VM lifecycle operations (use vmware-aiops), NSX networking (use vmware-nsx), or Kubernetes clusters (use vmware-vks).\n  For load balancing/AVI/AKO use vmware-avi.\ninstaller:\n  kind: uv\n  package: vmware-storage\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"vmware-storage\",\"uvx\"]},\"optional\":{\"env\":[\"VMWARE_STORAGE_CONFIG\",\"VMWARE_<TARGET>_PASSWORD\",\"VMWARE_<TARGET>_USERNAME\",\"VMWARE_AUDIT_APPROVED_BY\"],\"bins\":[\"vmware-policy\"]},\"homepage\":\"https://github.com/vmware-skills/VMware-Storage\",\"emoji\":\"🗄️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  vmware-policy auto-installed as Python dependency (provides @vmware_tool decorator and audit logging). All write operations audited to ~/.vmware/audit.db.\n  Credentials: Each vCenter/ESXi target requires a per-target password env var in ~/.vmware-storage/.env following the pattern VMWARE_<TARGET_NAME_UPPER>_PASSWORD (e.g., target \"my-vcenter\" → VMWARE_MY_VCENTER_PASSWORD). No webhooks or outbound network calls — this skill is local-only (stdio MCP + vSphere API). Audit logs written to ~/.vmware/audit.db (SQLite WAL, local only).\n---\n\n# VMware Storage\n\n> **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom. Source code is publicly auditable at [github.com/vmware-skills/VMware-Storage](https://github.com/vmware-skills/VMware-Storage) under the MIT license.\n\nVMware vSphere storage management — 14 MCP tools for datastores, iSCSI, vSAN, and Fibre Channel / multipath diagnostics.\n\n> Split from vmware-aiops for lighter context and local model compatibility.\n> **Companion skills**: [vmware-aiops](https://github.com/vmware-skills/VMware-AIops) (VM lifecycle), [vmware-monitor](https://github.com/vmware-skills/VMware-Monitor) (read-only monitoring), [vmware-vks](https://github.com/vmware-skills/VMware-VKS) (Tanzu Kubernetes), [vmware-nsx](https://github.com/vmware-skills/VMware-NSX) (NSX networking), [vmware-nsx-security](https://github.com/vmware-skills/VMware-NSX-Security) (DFW/firewall), [vmware-aria](https://github.com/vmware-skills/VMware-Aria) (metrics/alerts/capacity), [vmware-avi](https://github.com/vmware-skills/VMware-AVI) (AVI/ALB/AKO), [vmware-harden](https://github.com/vmware-skills/VMware-Harden) (compliance baselines).\n> | [vmware-pilot](../vmware-pilot/SKILL.md) (workflow orchestration) | [vmware-policy](../vmware-policy/SKILL.md) (audit/policy)\n\n## What This Skill Does\n\n| Category | Tools | Count |\n|----------|-------|:-----:|\n| **Datastore** | list all datastores, browse files, scan for OVA/ISO/OVF/VMDK images, list cached images | 4 |\n| **iSCSI** | enable adapter, show status, add target, remove target, rescan HBAs | 5 |\n| **vSAN** | cluster health summary, capacity overview (total/used/free), data-efficiency (dedup/compression) | 3 |\n| **FC / multipath** (read-only) | FC HBA inventory with WWPN/WWNN; per-device path state across hosts, datastore backing devices, path-count differences across hosts | 2 |\n\n## Quick Install\n\n```bash\nuv tool install vmware-storage==1.10.0\nvmware-storage init      # guided setup: writes config + .env (chmod 600, password grep-safe), then verifies\nvmware-storage doctor\n```\n\n## When to Use This Skill\n\n- Browse datastore files or scan for deployable images (OVA/ISO/VMDK)\n- Configure iSCSI: enable adapter, add/remove send targets, rescan storage\n- Check vSAN cluster health and capacity\n- Fibre Channel: list HBAs and WWPNs, find dead/disabled paths, compare path counts across a cluster, map a datastore to its devices\n- Any storage-focused VMware operation\n\n**Use companion skills for**:\n- VM lifecycle, deployment, guest ops → `vmware-aiops`\n- Inventory, health, alarms, events → `vmware-monitor`\n- Tanzu Kubernetes → `vmware-vks`\n- Load balancing, AVI/ALB, AKO, Ingress → `vmware-avi`\n\n## Related Skills — Skill Routing\n\n| User Intent | Recommended Skill |\n|-------------|-------------------|\n| Read-only monitoring, alarms, events | **vmware-monitor** |\n| Storage: iSCSI, vSAN, datastores | **vmware-storage** ← this skill |\n| VM lifecycle, deployment, guest ops | **vmware-aiops** |\n| Tanzu Kubernetes (vSphere 8.x+) | **vmware-vks** |\n| NSX networking: segments, gateways, NAT | **vmware-nsx** |\n| NSX security: DFW rules, security groups | **vmware-nsx-security** |\n| Aria Ops: metrics, alerts, capacity planning | **vmware-aria** |\n| Multi-step workflows with approval | **vmware-pilot** |\n| Compliance baselines (CIS / 等保 / PCI-DSS), drift detection, LLM remediation advisor | **vmware-harden** (`uv tool install vmware-harden`) |\n| Load balancer, AVI, ALB, AKO, Ingress | **vmware-avi** (`uv tool install vmware-avi`) |\n| Audit log query | **vmware-policy** (`vmware-audit` CLI) |\n\n## Common Workflows\n\n### Set Up iSCSI Storage on a Host\n\n**Pre-flight (judgment)**:\n- Network reachability: `vmkping <iscsi-target-ip>` from the ESXi host must succeed BEFORE adding the target. Adding an unreachable target leaves the host in a degraded state, retrying forever.\n- Adapter sanity: `iscsi status` first — if already enabled, do not \"re-enable\"; just add the target.\n- Idempotency: `add-target` is idempotent (re-adding same IP is a no-op), but `remove-target` is not safely reversible mid-IO. Always verify no LUNs from this target are in use before removing.\n- Existing targets: list them first; some sites add targets one-per-host while others use cluster-wide. Check site convention.\n\n**Steps**:\n1. `iscsi status esxi-01` → confirm adapter state and existing targets\n2. `iscsi enable esxi-01 --dry-run` then real (skip if already enabled)\n3. `iscsi add-target esxi-01 <ip> --dry-run` then real (auto-rescans on success)\n4. `iscsi status esxi-01` again → confirm target listed AND devices appearing\n5. If devices missing 30+ sec after add: `iscsi rescan esxi-01` once more, then check ESXi-side `vmkping` and target ACL\n\n### Find Deployable Images Across Datastores\n\n**Judgment**: image search is read-only and safe, but blind scanning of every datastore is slow on large estates. Filter first.\n\n1. `datastore list` → get the inventory; ignore datastores marked `inaccessible` or low free space\n2. `datastore scan-images <ds>` on the datastore most likely to hold images (typically named `iso-*`, `templates`, or central `nfs-shared`)\n3. If unsure where images live: scan multiple in parallel via separate calls; results are cached in the local registry\n4. `datastore browse <ds> --pattern \"*.iso\"` for ad-hoc searches; pattern is glob, not regex\n5. **If datastore not found**: name is case-sensitive. `datastore list --target <vc>` to verify exact spelling.\n\nFor filtered queries against the cache: use `list_cached_images` MCP tool with `image_type` and `datastore` parameters — avoids re-scanning.\n\n### vSAN Health Assessment\n\n**Judgment**: vSAN problems often masquerade as vSphere problems and vice-versa. Check both planes — if vSAN is healthy but VMs are slow, the issue is at the compute or network layer, not storage.\n\n1. `vsan health <cluster>` → look beyond green/red — check disk group state, network partitioning, and cluster member counts. A \"yellow\" disk group is the early warning of a failure.\n2. `vsan capacity <cluster>` → utilization > 70% triggers slack-space risk; > 80% impedes resync; never let prod cross 80%.\n3. Cross-check `vmware-monitor health alarms` for vSAN-related alarms (HCL warnings, network anomalies)\n4. **If vSAN not enabled** on this cluster: check cluster type via `vmware-monitor inventory clusters`; vSAN is opt-in, not default\n5. For deep investigation, follow [`references/investigation-protocol.md`](../vmware-aria/skills/vmware-aria/references/investigation-protocol.md) (in companion skill) — vSAN issues frequently fail the Mechanism criterion (capacity is correlated, not causal)\n\n### Check Fibre Channel Paths\n\n**Judgment**: report what vSphere observed, not a verdict. `standby` paths are normal on active/passive arrays, and equal path counts do not prove two independent fabrics. Zoning, array masking and switch health are out of scope.\n\n1. `paths devices --datastore <ds>` → dead/disabled paths behind one datastore, per host (devices needing attention sort first)\n2. `paths devices --cluster <c> --only-differences` → shared devices some hosts do not see, or see through a different number of paths; each host's `paths_total` shows which has fewer\n3. `paths devices --host <h> --adapter vmhba2` → what depends on one HBA; `only_paths_via_adapter: true` means that host has no other path to the device\n4. `paths fc-adapters --cluster <c>` → WWPNs to hand to the SAN team\n5. **If `complete` is false**: hosts in `hosts_not_read` were not read (the reason says `NoPermission` or the connection state). Name them as unknown — never report them as missing the device\n6. **If \"Scope required\"**: pass exactly one of `--cluster`, `--host` or `--datastore`; this tool does not read every host at once\n\n### Multi-Target Operations\n\nAll commands accept `--target <name>` to operate against a specific vCenter or ESXi host from your\n\nArchive v1.9.3: 8 files, 24126 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (7995b), references/capabilities.md (8403b), references/cli-reference.md (6889b), references/setup-guide.md (10638b), skill-card.md (2828b), SKILL.md (17815b), _meta.json (133b)\n\nArchive v1.9.2: 8 files, 24010 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (7995b), references/capabilities.md (8403b), references/cli-reference.md (6889b), references/setup-guide.md (10638b), skill-card.md (2441b), SKILL.md (17815b), _meta.json (133b)\n\nArchive v1.9.1: 8 files, 24015 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (7995b), references/capabilities.md (8403b), references/cli-reference.md (6889b), references/setup-guide.md (10638b), skill-card.md (2568b), SKILL.md (17815b), _meta.json (133b)\n\nArchive v1.9.0: 8 files, 24112 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (7995b), references/capabilities.md (8403b), references/cli-reference.md (6889b), references/setup-guide.md (10638b), skill-card.md (2759b), SKILL.md (17815b), _meta.json (133b)\n\nArchive v1.8.17: 8 files, 24174 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (7995b), references/capabilities.md (8403b), references/cli-reference.md (6889b), references/setup-guide.md (10575b), skill-card.md (2937b), SKILL.md (17905b), _meta.json (134b)\n\nArchive v1.8.16: 8 files, 24008 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (7995b), references/capabilities.md (8403b), references/cli-reference.md (6889b), references/setup-guide.md (10575b), skill-card.md (2535b), SKILL.md (17905b), _meta.json (134b)\n\nArchive v1.8.15: 8 files, 23886 bytes\n\nFiles: evals/evals.json (1258b), references/agent-guardrails.md (7995b), references/capabilities.md (8403b), references/cli-reference.md (6889b), references/setup-guide.md (10575b), skill-card.md (2324b), SKILL.md (17905b), _meta.json (134b)","readmeExcerpt":"Skill: vmware-storage Owner: zw008 Summary: Use this skill whenever the user needs to manage VMware storage — datastores, iSCSI targets, and vSAN clusters. Directly handles: browse datastores, scan for deployable images (OVA/ISO), configure iSCSI adapters and targets, check vSAN health and capacity, read-only Fibre Channel HBA/WWPN inventory and multipath path state. Always use this skill for \"list datastores\", \"add ","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"uv tool install vmware-storage==1.12.0\nvmware-storage init      # guided setup: writes config + .env (chmod 600, password grep-safe), then verifies\nvmware-storage doctor"},{"language":"bash","snippet":"# Default target (first in config.yaml)\nvmware-storage datastore list\n\n# Specific target\nvmware-storage datastore list --target prod-vcenter\nvmware-storage iscsi status esxi-lab --target lab-esxi"},{"language":"bash","snippet":"# Datastore\nvmware-storage datastore list [--target <name>]\nvmware-storage datastore browse <ds_name> [--path <subdir>] [--pattern \"*.ova\"]\nvmware-storage datastore scan-images <ds_name> [--target <name>]\n\n# iSCSI\nvmware-storage iscsi enable <host> [--dry-run]\nvmware-storage iscsi status <host>\nvmware-storage iscsi add-target <host> <ip> [--port 3260] [--dry-run]\nvmware-storage iscsi remove-target <host> <ip> [--port 3260] [--dry-run]\nvmware-storage iscsi rescan <host> [--dry-run]\n\n# vSAN\nvmware-storage vsan health <cluster> [--target <name>]\nvmware-storage vsan capacity <cluster> [--target <name>]\n\n# Fibre Channel / multipath (read-only)\nvmware-storage paths fc-adapters [--cluster <c> | --host <h>]\nvmware-storage paths devices (--cluster <c> | --host <h> | --datastore <ds>) [--device <naa>] [--adapter <vmhba>] [--only-differences]\n\n# Diagnostics\nvmware-storage doctor [--skip-auth]"},{"language":"bash","snippet":"chmod 600 ~/.vmware-storage/.env"},{"language":"bash","snippet":"uv tool install vmware-storage==1.12.0\nmkdir -p ~/.vmware-storage\ncp config.example.yaml ~/.vmware-storage/config.yaml\n# Edit config.yaml with your vCenter/ESXi targets\n\n# Add to ~/.vmware-storage/.env (create if missing, chmod 600):\n# VMWARE_MY_VCENTER_PASSWORD=<your-password>\nchmod 600 ~/.vmware-storage/.env\n\nvmware-storage doctor"},{"language":"text","snippet":"User (natural language)\n  ↓\nAI Agent (Claude Code / Goose / Cursor)\n  ↓ reads SKILL.md\nvmware-storage CLI or MCP server (stdio transport)\n  ↓ pyVmomi (vSphere SOAP API)\nvCenter Server / ESXi\n  ↓\nDatastores / iSCSI / vSAN"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: vmware-storage\ndescription: >\n  Use this skill whenever the user needs to manage VMware storage — datastores, iSCSI targets, and vSAN clusters.\n  Directly handles: browse datastores, scan for deployable images (OVA/ISO), configure iSCSI adapters and targets, check vSAN health and capacity, read-only Fibre Channel HBA/WWPN inventory and multipath path state.\n  Always use this skill for \"list datastores\", \"add iSCSI target\", \"check vSAN health\", \"browse datastore files\", \"scan for OVA images\", \"dead paths\", \"FC HBA WWPN\", or any storage-related VMware task.\n  Do NOT use for VM lifecycle operations (use vmware-aiops), NSX networking (use vmware-nsx), or Kubernetes clusters (use vmware-vks).\n  For load balancing/AVI/AKO use vmware-avi.\ninstaller:\n  kind: uv\n  package: vmware-storage\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"vmware-storage\",\"uvx\"]},\"optional\":{\"env\":[\"VMWARE_STORAGE_CONFIG\",\"VMWARE_<TARGET>_PASSWORD\",\"VMWARE_<TARGET>_USERNAME\",\"VMWARE_AUDIT_APPROVED_BY\"],\"bins\":[\"vmware-policy\"]},\"homepage\":\"https://github.com/vmware-skills/VMware-Storage\",\"emoji\":\"🗄️\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  vmware-policy auto-installed as Python dependency (provides @vmware_tool decorator and audit logging). All write operations audited to ~/.vmware/audit.db.\n  Credentials: Each vCenter/ESXi target requires a per-target password env var in ~/.vmware-storage/.env following the pattern VMWARE_<TARGET_NAME_UPPER>_PASSWORD (e.g., target \"my-vcenter\" → VMWARE_MY_VCENTER_PASSWORD). No webhooks or outbound network calls — this skill is local-only (stdio MCP + vSphere API). Audit logs written to ~/.vmware/audit.db (SQLite WAL, local only).\n---\n\n# VMware Storage\n\n> **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom. Source code is publicly auditable at [github.com/vmware-skills/VMware-Storage](https://github.com/vmware-skills/VMware-Storage) under the MIT license.\n\nVMware vSphere storage management — 14 MCP tools for datastores, iSCSI, vSAN, and Fibre Channel / multipath diagnostics.\n\n> Split from vmware-aiops for lighter context and local model compatibility.\n> **Companion skills**: [vmware-aiops](https://github.com/vmware-skills/VMware-AIops) (VM lifecycle), [vmware-monitor](https://github.com/vmware-skills/VMware-Monitor) (read-only monitoring), [vmware-vks](https://github.com/vmware-skills/VMware-VKS) (Tanzu Kubernetes), [vmware-nsx](https://github.com/vmware-skills/VMware-NSX) (NSX networking), [vmware-nsx-security](https://github.com/vmware-skills/VMware-NSX-Security) (DFW/firewall), [vmware-aria](https://github.com/vmware-skills/VMware-Aria) (metrics/alerts/capacity), [vmware-avi](https://github.com/vmware-skills/VMware-AVI) (AVI/ALB/AKO), [vmware-harden](https://github.com/vmware-skills/VMware-Harden) (compliance baselines).\n> | [vmware-pilot](../vmware-"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"vmware-storage\",\n  \"version\": \"1.12.0\",\n  \"publishedAt\": 1789915968885\n}"},{"path":"references/agent-guardrails.md","content":"# Operating vmware-storage with a local / small model\n\nClaude-class models drive this skill without special instruction. Smaller and\nlocally-hosted models — Llama 3.3 70B, Qwen, Mistral, and similar, served\nthrough Goose, Ollama, or OpenShift AI — need explicit operating rules to call\ntools reliably.\n\nThis page exists because an operator wrote those rules by hand first. The\nguardrails below are adapted, with thanks, from the working configuration\n[@juanpf-ha](https://github.com/juanpf-ha) developed while running\nvmware-monitor and vmware-aria against a production vSphere estate with Llama\n3.3 70B FP8 on an on-prem H100\n([VMware-AIops#31](https://github.com/vmware-skills/VMware-AIops/issues/31)). The\ncross-skill rules are identical across this family; the parts below marked\nvmware-storage are specific to this skill.\n\nvmware-storage exposes 14 MCP tools, 4 of which change state. The write\nsurface is small but sharp: removing an iSCSI send target can make LUNs — and\nevery VM living on them — inaccessible.\n\n> **Disclaimer**: This is a community-maintained open-source project and is\n> **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom\n> Inc.** \"VMware\" and \"vSphere\" are trademarks of Broadcom.\n\n---\n\n## First: the rules you no longer need to write\n\nSeveral guardrails from the original configuration are now enforced by the\nskill itself. Prompt instructions are advisory — a model can ignore them.\nThese are structural, so it cannot.\n\n| Guardrail you would otherwise prompt for | Now enforced by |\n|---|---|\n| \"Preview the change before applying it\" | **`confirm` defaults to false.** A call to any of the 4 write tools without `confirm: true` changes nothing and returns `blast_radius`. Previewing is the default path, not a convention the model has to remember to honour. |\n| \"Don't cut off storage that is in use\" | **Refusal.** `storage_iscsi_remove_target` with `confirm: true` is refused when a datastore would lose every path, or when any path or static target behind the send target cannot be attributed. |\n| \"Use explicit limits for queries that may return large amounts of data\" | **The list envelope.** The four datastore read tools return `{items, returned, limit, total, truncated, hint}`, so the model reads truncation instead of guessing at it. All four enumerate their collection in full, so `total` is the real count and `truncated` is always `false`. |\n| \"If a listing came back empty, say so rather than claiming the call failed\" | Same envelope. Empty `items` with `truncated: false` means checked-and-none — a stated result, not a silence the model has to interpret. |\n| \"Log every state change you make\" | **The `@vmware_tool` decorator.** Every operation is recorded to `~/.vmware/audit.db` before the model sees the result, and policy rules are evaluated ahead of execution. `storage_iscsi_remove_target` is classified `risk:high` and goes through the policy confirmation gate. |\n\n---\n\n## The system prompt\n\nEverything below still benef"},{"path":"references/capabilities.md","content":"# VMware Storage Capabilities\n\nAll 11 MCP tools exposed by `vmware-storage-mcp`, organized by category.\n\n## Automation Level Reference\n\nEach operation is classified by autonomy level per the Enterprise Harness Engineering framework:\n\n| Level | Meaning | Agent autonomy | Examples in this skill |\n|:-:|---|---|---|\n| **L1** | Read-only, raw data | Always auto-run | `list_all_datastores`, `browse_datastore`, `scan_datastore_images`, `list_cached_images`, `storage_iscsi_status`, vSAN status queries |\n| **L2** | Read + analysis / recommendation | Always auto-run | datastore capacity analysis, image registry queries, iSCSI target health correlation |\n| **L3** | Single write — user must approve | Only after explicit confirmation; high-risk ops require double-confirm + `--dry-run` (see Confirm column) | `storage_iscsi_enable`, `storage_iscsi_add_target`, `storage_iscsi_remove_target`, vSAN cluster ops |\n| **L4** | Multi-step plan / apply workflow | Plan generation auto; apply gated by user approval | *(roadmap — multi-host iSCSI rollout, vSAN expansion plans)* |\n| **L5** | Auto-remediation from learned pattern | Pattern library only; requires `risk:low` + `reversible:true` + `repeatable:true` + signed approval | **PoC pattern (v1.5.16+)**: [`patterns/iscsi-target-stale-rescan.yaml`](../../../patterns/iscsi-target-stale-rescan.yaml) — scans for stale iSCSI devices (`devices_inaccessible_count > 0`, missing expected devices, or `last_rescan_age_minutes > 60`); action: invoke `storage_rescan` on the affected `(host, target)`; classified low-risk because the rescan is idempotent and non-destructive (no data, config, or VM state is modified). Schema only — **not yet enforced by the runtime**. |\n\n**Notes**:\n- L1/L2 tools are always safe for agents to call without confirmation.\n- L3 tools always pass through the `@vmware_tool` decorator: connection check → policy check → audit log → double-confirm.\n- L5 PoC pattern (`patterns/iscsi-target-stale-rescan.yaml`, v1.5.16+) is a **reference design**: it documents the candidate trigger / action / validation / circuit-breaker shape under `schema_version: 1` (see [vmware-policy auto-remediation pattern docs](https://github.com/vmware-skills/VMware-Policy/blob/main/docs/auto-remediation-patterns.md)). The pattern is `approval.status: poc_unsigned` and will only become live after `success_count_required: 5` + `failure_count_max: 0` + `distinct_operators_required: 2` + `days_observed: 90` are met and the pattern is signed.\n\n## Datastore (4 tools)\n\n| Tool | Description | Parameters | Risk | Confirm |\n|------|-------------|------------|:----:|:-------:|\n| `list_all_datastores` | List datastores with capacity, usage %, VM count | `target` (string, optional) | Low | No |\n| `browse_datastore` | Browse files with optional path and glob pattern | `datastore` (string, **required**), `path` (string, optional), `pattern` (string, optional), `target` (string, optional) | Low | No |\n| `scan_datastore_images` | Find OVA/ISO/OVF/VMDK dep"},{"path":"references/cli-reference.md","content":"# CLI Reference\n\nComplete command reference for `vmware-storage` CLI.\n\n## Global Options\n\nAll commands accept these options:\n\n| Option | Description |\n|--------|-------------|\n| `--target <name>` | Target name from `~/.vmware-storage/config.yaml` (defaults to first target) |\n| `--config <path>` | Override config file path |\n| `--help` | Show command help |\n\n## Datastore Commands\n\n### `datastore list`\n\nList all datastores with capacity, usage, and VM count.\n\n```bash\nvmware-storage datastore list\nvmware-storage datastore list --target my-vcenter\n```\n\nOutput columns: Name, Type, Total GB, Free GB, Usage %, VMs.\nUsage above 85% is highlighted in red.\n\n### `datastore browse`\n\nBrowse files in a datastore directory. Supports glob pattern filtering.\n\n```bash\n# Browse root of a datastore\nvmware-storage datastore browse datastore01\n\n# Browse a subdirectory\nvmware-storage datastore browse datastore01 --path \"iso-images\"\n\n# Filter by pattern\nvmware-storage datastore browse datastore01 --pattern \"*.ova\"\nvmware-storage datastore browse datastore01 --path \"templates\" --pattern \"*.iso\"\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `ds_name` | Yes | - | Datastore name (case-sensitive) |\n| `--path` | No | `\"\"` (root) | Subdirectory path within the datastore |\n| `--pattern` | No | `\"*\"` | Glob pattern to filter files |\n\nOutput: JSON array of file objects with `name`, `size_mb`, `type`, `modified`, `ds_path`.\n\n### `datastore scan-images`\n\nScan a datastore for deployable images (OVA, ISO, OVF, VMDK).\n\n```bash\nvmware-storage datastore scan-images datastore01\nvmware-storage datastore scan-images datastore01 --target prod-vcenter\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `ds_name` | Yes | - | Datastore name |\n\nScans for patterns: `*.ova`, `*.ovf`, `*.iso`, `*.vmdk`. Results are sorted by name.\n\n## iSCSI Commands\n\n### `iscsi enable`\n\nEnable the software iSCSI adapter on an ESXi host.\n\n```bash\nvmware-storage iscsi enable esxi-01\nvmware-storage iscsi enable esxi-01 --dry-run\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n| `--dry-run` | No | `false` | Preview the operation without executing |\n\n**Safety**: Requires double confirmation (two prompts). If the adapter is already enabled, returns current HBA device and IQN without making changes.\n\n### `iscsi status`\n\nShow iSCSI adapter status and configured send targets.\n\n```bash\nvmware-storage iscsi status esxi-01\n```\n\n| Argument/Option | Required | Default | Description |\n|----------------|:--------:|---------|-------------|\n| `host_name` | Yes | - | ESXi host name |\n\nOutput: JSON with `enabled`, `hba_device`, `iqn`, and `send_targets` (list of address/port pairs).\n\n### `iscsi add-target`\n\nAdd an iSCSI send target to a host and automatically rescan storage.\n\n```bash\nvmware-stor"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1987,"uniquenessScore":41,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T04:07:22.221Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T04:07:22.221Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T12:27:01.492Z","emptyReason":null},"items":[{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-10T18:48:31.762Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}