Releases: vmware-skills/VMware-Storage
Release list
v1.8.17 — a dropped connection no longer keeps itself alive
Every connect() registered an atexit cleanup that closes over the
ServiceInstance, and atexit held that closure — and so the SI, its stub and
its socket — until the process exited. Nothing ever unregistered it. A
long-running MCP server that reconnects after each session expiry therefore
pinned one dead connection per reconnect, and at exit would run a Disconnect
against every session it had ever opened.
Measured before the fix: 20 evict-and-reconnect cycles left all 20 evicted
ServiceInstance objects reachable. The id(si) side stores were correctly down
to one entry throughout — the side-store discipline was never the leak, the
registration was.
_release_si() now takes the handler back off at both points that drop a
connection: the eviction inside connect() and disconnect(). Five repos had
the identical shape, so family_smoke gained a gate for it (154 → 155).
Not WeakKeyDictionary, which looks like the obvious fix and is a regression:
pyVmomi's ManagedObject.__eq__ compares moId, class and serverGuid, and every
ServiceInstance carries moId 'ServiceInstance' with serverGuid None. Two
vCenters collapse into one entry — connecting to the second silently hands the
first one's verify_ssl to both. Keying by id() is right precisely because
it is identity.
v1.8.16 — one answer per .env, on every platform
.env permissions are decided by vmware_policy.fsperms instead of POSIX mode
bits. On Windows a single command printed both a red "has permissions 0o666
(should be 600). Run: chmod 600" from this hot path — where chmod does nothing
— and a green "this platform does not express file permissions as POSIX mode
bits ... run: icacls" from doctor, about the same file in the same run. doctor
had been moved to the three-state check and the path that runs on every command
had not. An unmeasurable platform is now silent here rather than loudly wrong.
v1.8.15
The suite now runs on a cp936 machine. Round 3 of the VCF 9 field testing ran
on Windows Server 2025 with locale cp936. Across the family four repos' suites --
1687 tests -- never executed at all, dying at collection reading our own UTF-8
sources, and 101 more failed the same way. Most of those were the tests that
verify the destructive-operation guardrails: the guardrails were fine, the tests
that check them could not open a file. On the UTF-8 CI every one of them was
green. A security test that cannot run is not a security test.
Every text read and write here names its encoding now, tests/ included -- the
previous round fixed only the package, which is why this came back. A gate in
family_smoke scans both trees by AST, and the whole family's suites were re-run
under an ASCII locale to confirm: 15 of 15 green, from 1 of 15.
--help no longer dies on a console that cannot encode it. On any console
whose encoding cannot carry the characters in our own help text, --help exited
with a UnicodeEncodeError traceback -- unavailable exactly on the machines
where it is most needed. Four repos were affected; the handler is now relaxed in
all fifteen so a glyph degrades instead of killing the command.
Its environment resolver no longer answers for other skills.
set_environment_resolver wrote one process-global slot and twelve servers
registered into it at import time, so the last one won for all of them --
measured taking a freeze-production-writes rule from DENY to ALLOW on another
skill's production target. Registration is keyed by skill now (requires
vmware-policy 1.12.0).
The .env permission check stopped being permanently red on Windows. It was
POSIX-only, and chmod 600 there exits 0 without changing any bits -- so
doctor printed a failure on every run with a remedy that could not clear it.
Three states now, via vmware_policy.fsperms: only a demonstrated exposure
fails, and "this platform cannot answer" says so and offers icacls.
Unknown tool arguments are refused instead of dropped. The schema declared
additionalProperties: false and the runtime accepted them anyway, so a filter
argument whose name a model guessed wrong returned the unfiltered result with
nothing to indicate anything had been discarded. Fixed in vmware-policy 1.12.0
and in force here.
Requires vmware-policy 1.12.0.
v1.8.14 — the healthy datastore was the one that crashed
Two crashes and a placeholder that stood in for a real answer.
datastore list failed every time on a healthy datastore: an empty style
string rendered []12.5%[/], which Rich parses as markup and rejects. Only the
normal case crashed, which is how it shipped. A datastore legitimately named
[SSD] prod hit the same parser.
vsan_health hardcoded overall_health: "unknown" under a note claiming a full
health check was out of reach. It is not — vsanapiutils ships inside pyvmomi
and the health system sits beside the config system this skill already uses. The
placeholder was the worst possible one, because vSAN returns "unknown" itself:
"we did not ask" was spelled identically to "vSAN does not know", and here it
stood in for red.
The suite also stopped writing to the operator's real audit database.
The vmware-policy floor moves to >=1.11.0. Policy 1.11.0 stops the engine
failing open: on a host whose locale is not UTF-8, reading rules.yaml raised a
decode error that was swallowed, and a freeze-production-writes rule came back
ALLOW. No new API is used here, so the floor could have stayed — it is raised
because leaving it low means a user resolving 1.10.0 keeps the permissive engine
and the fix never reaches them. One behaviour travels with it: on a host whose
rules file cannot be read, operations move from all-allowed to all-denied.
VMWARE_POLICY_DISABLED=1 is checked above the rules, so the escape hatch does
not itself depend on them loading.
Also in this release: the suite no longer appends to the operator's real
~/.vmware/audit.db. It held over 30,000 rows dominated by tool names nobody
had invoked, including 1,400 entries for a destructive operation that never
happened — an audit trail carrying test fiction cannot answer the question it is
kept for.
v1.8.13 — the schema an agent reads now carries the descriptions
Parameter descriptions reach the JSON schema for the first time. An MCP client
sees the schema, not the docstring, and this repo's coverage of description
and additionalProperties was 0% — while nearly every parameter was already
described in an Args: block no client ever receives.
Measured on a real VCF 9.1 estate, the gap produced a silent failure with no
error at any stage: a parameter name guessed wrong is discarded and the tool
returns the full unfiltered result; a value guessed wrong (power_state= "running") returns 0 rows where there were 11.
vmware-policy 1.10.0's describe_tool_parameters copies what is already
written, so the docstring is now load-bearing and the two cannot drift apart. It
removes the Args: block from the description once copied — both travel in
every tools/list response, so leaving it bills the same sentences twice
against the manifest's token budget. additionalProperties is closed: an open
schema is room for a model to invent arguments that are then silently
discarded, which is the other half of the same failure.
The vmware-policy floor moves to >=1.10.0. Older releases have no
describe_tool_parameters, and resolving one gives an ImportError at server
start rather than a missing feature.
The Chinese README also said 11 tools where there are 12, and quoted
vmware-aiops at 49 tools where it now has 60 — a cross-skill reference drifts
just as quietly as an internal one.
v1.8.12 — reporting what was not read, instead of answering for it
Found against a real VCF 9.1 estate where four of eight ESXi hosts were
notResponding. vCenter keeps answering for such a host out of its own cache,
with no error and no marker, so a read "succeeds" and looks authoritative.
vsan_health returned disk_groups: [] and said nothing about the four hosts
it could not read — the exception was logged and the host skipped. An empty
list is indistinguishable from "this cluster has no disk groups", and this
cluster's real overallHealth was red. Every host that does not contribute is
now recorded with its connectionState and the reason, counted in
hosts_read/hosts_not_read, flagged by disk_groups_complete, and named in
the message — the part a chat client reliably renders.
vsan_capacity returned total/used/free all 0 with no message, having
never consulted summary.accessible: a healthy-looking empty datastore. The
flag is now read as three states — false returns nulls and says why, null
(an older summary that did not say) leaves the figures standing and reports the
unknown rather than resolving it to true.
storage_iscsi_status crashed with AttributeError: 'NoneType' object has no attribute 'storageDevice', because HostSystem.config is None for an
unreachable host. The obvious repair was the wrong one: _get_iscsi_hba's
None already means "no software iSCSI adapter" and renders as
enabled: false, so guarding the attribute would have traded a crash for a
confident false claim about a machine nobody reached. It raises a teaching error
naming the state instead.
doctor cleared an estate it had not checked — it authenticated only the
default target, and it inspected a different config file from the one the tools
load. load_config never consulted VMWARE_STORAGE_CONFIG at all while the MCP
server did, so the agent's tools opened one file and the CLI and doctor opened
another. The precedence now lives in one resolve_config_path. This changes
CLI behaviour: vmware-storage now honours that variable, where it previously
ignored it.
Also: server.json never started the MCP server, and the Dockerfile could not
build the wheel it installs.
v1.8.11 — two wrong numbers: the server's own version, and the advertised tool count
Both defects were invisible to the test suites and both were user-facing.
- The MCP server reported the SDK's version as its own.
FastMCPaccepts no
versionargument and leaves the lowlevel server's atNone; with itNone
the SDK answersinitializewith its OWN version. Every skill in the family
therefore told its client it was mcp 1.29.1 — a number that exists for no
package here, and one that would change with an SDK bump and no code change of
ours. Verified end to end rather than by reading: unset the field and a probe
server reports the installed SDK's version; set it and it reports ours. - server.json advertised a stale tool count. That number is what MCP Registry
publishes and what the plugin manifest and marketplace copy, so one stale
integer was wrong in three public places. Corrected against the registered
tools: 11 advertised, 12 real. README and SKILL.md were already right.
Also new: this repo is installable as a Claude Code plugin
(/plugin install vmware-storage@vmware-skills). The skill and its MCP server arrive in
one step; nothing is duplicated, the manifest points at the existing skills/
tree. family_smoke gained three gates — the server's reported version, the plugin
manifest's agreement with pyproject, and the advertised tool count against the
live registration.
v1.8.10 — VCF 9.1 tools + review hardening
vSAN 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).
Community project — not affiliated with VMware/Broadcom.
v1.8.9 — vmware-skills org + registry namespace
Repo moved to the vmware-skills GitHub org (old zw008 links redirect). MCP Registry server renamed to io.github.vmware-skills/*; old io.github.zw008/* deprecated. In-repo links updated. See RELEASE_NOTES.md.
v1.8.8 — CLI writes route through policy + audit (@guarded)
v1.8.8 — CLI writes now route through policy + audit, exactly like the MCP tools
Every state-changing CLI command is now wrapped by @guarded, the CLI counterpart
to the MCP @vmware_tool decorator: it runs the same vmware-policy guard()
authorization and writes the same audit_call() row to ~/.vmware/audit.db. A
delete/disable/destructive command run through a shell is now authorized and
recorded exactly like the equivalent MCP tool — closing the gap where CLI writes
bypassed policy and landed only in the legacy per-skill log (HLD I-1/I-8).
- a policy
denyrule now refuses the operation on the CLI with a teaching line
naming the rule that fired, not a traceback - the legacy per-skill audit log is still written this release (dual-write); it is
removed at 2.0 - requires vmware-policy >= 1.8.8 (the release that adds the shared
guardedcore) - a regression test derives the write-command set from the MCP
[WRITE]markers and
asserts every one is@guarded, so a new write command cannot ship unguarded
Also carries the environment-field docstring correction (an optional label a deny
rule may scope to — there is no "warn now / refuse next major" gate).