A capability is a discoverable fact about this package build and the attached adapter. capabilities.get() returns a structured matrix (static ∪ runtime), not a flat list of strings.
OpenFeature and the wire still say flagKey. The matrix still pins static.features.flags: true even though the product noun is control point.
Why it exists
Language surfaces diverge (registration, typed getters, local adapters). Harnesses and defensive app code should ask the client what it can do instead of sniffing versions or copying another language’s namespace.
When to use it
- Gate optional paths (
localEvaluation, exposureEmission, remoteEvaluation)
- Confirm
guardrails is false before you assume ramp control exists in-process
- Invoke a named operation dynamically and accept
UnsupportedCapability
You do not need this for a normal evaluate + record-outcome path.
How it relates
In-app “bind capabilities per environment” is undefined in recovered console copy and NEEDS VERIFICATION. It is not this SDK API.
What get() returns
Shape: spec/capabilities.schema.json.
static (compile-time)
runtime (adapter + config)
Canonical operations
Identical names across languages:
API
Unknown names on invokeCapability / invoke / Invoke degrade with UnsupportedCapability. They never throw.
Guardrails are a stub
Every language ships types so the name is stable, and every call returns UnsupportedCapability (often with degraded: true). The static matrix reports guardrails: false.
Do not write a how-to for client-side auto-rollback. Console Block / rollback copy is not this API.