@visiq/harness SDK and its sibling packages
evolve: what a version number promises today, the invariants that hold
regardless of version, and the compatibility commitment that takes effect at
v1.0.
This is about the SDK — the client library you install (
@visiq/harness,
visiq, and the other language bindings). The OEM Partner API has its own,
separate versioning contract with a dated version header and a 12-month
deprecation window — see Versioning & deprecation.Pre-1.0: no wire-compatibility guarantee yet
The VisIQ SDK is pre-1.0 (0.x): there is no wire-compatibility guarantee yet. Breaking changes may ship in any minor release until v1.0 GA. This is exactly what a0.x version already means under
Semantic Versioning 2.0: “anything MAY
change at any time; the public API SHOULD NOT be considered stable.” A minor
bump (0.2.0 → 0.3.0) is allowed to remove or rename a field, change a
default, or tighten a shape — and our published changelog does exactly that
(for example, 0.2.0 made fleet.heartbeat() require an argument that earlier
releases did not).
We are treating the pre-launch window as deliberate design time: the point of
staying on 0.x is to get the wire contract right before we commit to it. Once
a construct is in a v1.0 API it is expensive to change; pinning that contract
prematurely would trade a few months of convenience for years of carrying a
shape we later regret. So the posture is intentional, not an oversight.
What this means for you today
- Pin an exact version and upgrade deliberately. Don’t float a range across a minor boundary in an unattended pipeline.
- Read the changelog before upgrading. Every breaking change is called out
under a
Breaking/Removedheading in that package’s changelog. - Expect the surface to keep moving until the v1.0 line below is in effect.
Two invariants we hold even at 0.x
“Pre-1.0” governs the shape of the SDK surface — the types, fields, and function signatures you compile against. Two properties are not on the table even while we are pre-1.0, because a governance product cannot be casual about them. Both are enforced by the release process and proven continuously, not left to reviewer diligence.1. The wire contract fails closed, and the SDK ships first
The control plane and the SDK talk over a rule bundle — a document of outcome verbs (permit, deny, approval_required, mask, redact,
escalate), fields, and multi-valued operations[] facets (retrieval,
action, delegation). Two rules govern that document forever:
- Additive-only, SDK ships first. The control plane never emits a bundle
construct — a new outcome verb, a new field, or a new
operations[]facet — that the reading SDK cannot already enforce. The SDK that understands a construct is published before the plane starts emitting it. This is the tolerant-reader principle applied in the safe direction: readers tolerate what they don’t need, but the writer never gets ahead of the readers on anything load-bearing. - Fail closed on the unrecognized. Every SDK treats a construct it does not recognize as MUST-UNDERSTAND: it does not silently ignore it and proceed. A feature-flag SDK can afford to skip an unknown flag; a governance SDK cannot skip an unknown restriction. So an unrecognized outcome or an unparseable bundle resolves to the fail-closed outcome for a confirmed-enforcing agent — deny the action, suppress the document — never fail open. This is the same fail-closed ladder the runtime already follows when a bundle is missing or a mask fails (see Local evaluation).
2. Every shipped plugin tracks the current stable host
The CLI plugins — Claude Code and OpenClaw — are the one place our governance rides inside another program’s process. For each, the invariant is: the shipped plugin both registers with and actually enforces against the current stable release of its host. It is not enough to load — a plugin that installs but no longer intercepts the host’s tool calls is worse than none, because it looks governed. We verify this daily against the real host binary, not a mock: a canary installs the current stable Claude Code and OpenClaw, drives a tool call that a rule denies, and asserts the call was actually blocked and recorded. A host release that moves an interception point turns the canary red before it can reach a user.At v1.0: the compatibility window
v1.0 is where the wire contract freezes and the SDK enters a supported compatibility window. From GA:- We support any SDK released in the last 12 months. A control plane will
interoperate with every SDK version published within the trailing twelve
months, across all the SDKs we distribute — TypeScript (
@visiq/harnesson npm), Python (visiqon PyPI), Ruby (visiqon RubyGems), Java (com.visiqlabs:visiq-sdkon Maven Central), and the Rust and Go bindings distributed via git/module. You get a full year to adopt a new release, not a flag day. - Breaking changes move to major versions. After 1.0, a change that removes
or renames a surface, changes a default, or tightens a shape ships in the next
major (
2.0.0), with the prior major supported through the window above. Minors and patches stay additive and backward-compatible.
- SemVer 2.0 — the pre-1.0 / post-1.0 split and the major-for-breaking rule are SemVer verbatim.
- Kubernetes version-skew policy — a bounded, published window in which older and newer components are guaranteed to interoperate, so operators upgrade on their own schedule.
- Tolerant-reader / schema BACKWARD & FORWARD compatibility — the additive-only, fail-closed-on-unknown discipline above is the standard contract-evolution posture from schema-registry ecosystems (Avro/Protobuf), applied in the direction a governance system requires.