An SDK for your language.
Five families. Each covers every contract it offers, whole — and the conformance suite is what says so.
All three contracts in one module: Plugins, interface clients and administrative tooling. The reference clients are written with it.
go get github.com/yoke-project/yoke-sdk-go/pluginyoke-sdk-goPlugins, on Tokio, in one crate over a base the libraries to come will share.
cargo add yoke-sdkyoke-sdk-rustPlugins, on asyncio, in one wheel over a base the libraries to come will share.
pip install yoke-sdkyoke-sdk-pythonPlugins, in C11, with protobuf-c and gRPC's core C API. The interface library follows, for panels drawn with LVGL.
gh release download -R yoke-project/yoke-sdk-cyoke-sdk-cPlugins, in C++17, with protoc and gRPC's C++ plugin. The interface library follows, for panels drawn with Qt.
gh release download -R yoke-project/yoke-sdk-cppyoke-sdk-cppHow it works
Pick the family for your language
Go, Rust, Python, C or C++, each its own repository. Every family offers the plugin contract; Go offers the interface and administrative ones too, and C and C++ have the interface contract coming. A contract a family offers, it covers whole.
Write against the contract
A Plugin declares in code what it is — its queries, commands, streams and the capabilities that govern them — and the same declaration writes its Manifest. Each family is shaped the way its own language is written, not as a copy of the others.
Run it under the Core
The Core launches it, admits it against what the operator granted, and routes its messages without reading what they carry.
A Plugin in each language
A clock that answers one question — the time now — written with each family. It declares the query and the capability that governs it, and the same declaration writes its Manifest.
package main
import (
"context"
"os"
"strconv"
"time"
"github.com/yoke-project/yoke-sdk-go/plugin"
)
var declaration = plugin.Declaration{
ID: "com.example.hello.clock",
Queries: []string{"clock.now"},
Capabilities: []plugin.Capability{
{Name: "query.now.answer", Governs: plugin.Object{Query: "clock.now"}},
},
}
func main() {
if len(os.Args) == 2 && os.Args[1] == "manifest" {
os.Stdout.Write(declaration.Manifest())
return
}
u, err := plugin.Start(context.Background(), declaration)
if err != nil {
panic(err)
}
u.Health(0, "keeping time")
for event := range u.Events() {
if q, ok := event.(plugin.Question); ok && q.Type == "clock.now" {
u.Answer(q, []byte(strconv.FormatInt(time.Now().Unix(), 10)))
}
}
}$ mkdir clock && cd clock # main.go goes here $ go mod init example.com/clock $ go get github.com/yoke-project/yoke-sdk-go/plugin $ go build -o clock . $ ./clock manifest manifest: 1 id: com.example.hello.clock protocol: 1 queries: - id: clock.now capabilities: - name: query.now.answer governs: query: clock.now
Run it — the same for every language
$ mkdir hello && cd hello $ yoke-compose init com.example.hello $ install -D ../clock/clock components/plugins/clock $ components/plugins/clock manifest > manifests/com.example.hello.clock.yaml $ yoke-compose add unit clock --kind plugin --plugin com.example.hello.clock --exec components/plugins/clock $ yoke-compose build --out .. $ yoke app install ../com.example.hello-*.yoke $ yoke instance create com.example.hello --name bench $ yoke instance start bench $ until yoke core status --instance bench > /dev/null 2>&1; do sleep 1; done # start asks the guardian; the Core answers a moment later $ yoke plugin grant com.example.hello.clock query.now.answer
The Plugin is admitted with nothing granted: its declaration asks, the operator grants. Once the grant reaches it at its next admission, any interface allowed to may ask it the time.
