How your app consumes a component
Amazon publishes each native capability as a component carrying a component id, a unique string in reverse domain notation. The API Reference documents them, for examplecom.amazon.kepler.audio.
To use a capability, resolve its component by id, then query that component for the interface you need. You call the interface through its C++ projection, which your build generates from that package’s IDL.
That id is the component’s whole identity to your app. Your code doesn’t know where the implementation lives, or whether it lives in a shared object or in-process, and it doesn’t need to.
Why the interfaces stay binary-stable
With an API, software components are combined at the source level. You compile them together to produce executables and shared libraries. A change on the other side means recompiling your own. A stable Application Binary Interface (ABI) works differently. Components compile independently of one another, then combine safely at runtime. This air gapping decouples dependencies from dependents. For your app, the implementation behind an interface can be rebuilt, patched, or replaced without you recompiling. Using a stable ABI, an author can write components in their preferred language, as long as every party communicates through the agreed ABI.Interfaces, packages, and projections
Every contract has two sides. A provider implements the contract, and a consumer uses it. OmniKit’s tools serve both sides from the same source. Contracts are authored as language-neutral interfaces in an interface definition language (IDL). An interface describes the behavior of a component, never its implementation. Related interfaces live together in packages. For each supported language, the IDL compiler reads a package and generates a language projection: the API you program against in that language. For interfaces, their generated projections do the crossing. They adapt your language’s calling convention to the stable C ABI that the two sides meet at, through that language’s foreign function interface (FFI). The result presents the contract as a natural API, so each party works in the style of its own language. For native Vega apps, the compiler generates C++ bindings and headers, and your build compiles them into a library your app links against. Every language projection implements the same ABI, a C ABI vtable. Binaries compiled from different languages therefore interoperate, so a C++ app can call a component implemented in another language. Neither side takes a compile-time dependency on the other.
Each party interacts only with its own projections, so the two sides meet at the ABI rather than in source. The languages in the diagram are illustrative. Either side could be written in any supported language.
Example: one contract, three independent parties
This example has three parties: two device vendors that provide components, and your app, which consumes one or both. The first vendor provides a Wi-Fi device implementation. The vendor authors an IDL describing the behavior of a generic device, generates a language projection, and implements a component with the idcom.example.wifi. The vendor then publishes the component binary, the component id, and the IDL.
Your app needs that Wi-Fi device. Take the published IDL and generate your own language projection. Ship the vendor’s component binary alongside your app, then load the component at runtime by id.
A second vendor ships a competing Wi-Fi device. That vendor reuses the IDL the first vendor already published, then publishes its own component binary under the id com.othercompany.wifi.
To widen device support for your customers, add the second component id as another device and patch your app. None of the three parties coordinate beyond publishing binaries that conform to the same IDL contract.
In the Vega native interfaces, Amazon is the vendor and your app is the consumer.
How interfaces change over time
A published IDL package doesn’t change. Its name, path, and contents all feed the structural hashes of the types inside it, so editing any of them produces a different contract. Existing binaries would stop interoperating with it. Interfaces grow by addition instead. When a capability needs a new method, Amazon publishes a new interface that extends the existing one, with a version number appended to its name.IAudioEffect is followed by IAudioEffect2 through IAudioEffect6, and IDisplayListener by IDisplayListener2 and later versions.
For your app, this means two things. Code written against an existing interface keeps working, because that interface is never edited. To reach newer capability, query the component for the newer interface, as described in How your app consumes a component.

