github.com/brokenbots/criteria-go-adapter-sdk

Go SDK for building Criteria adapters (protocol v2): serve(), helpers, manifest emit


License
Other
Install
go get github.com/brokenbots/criteria-go-adapter-sdk

Documentation

criteria-go-adapter-sdk

Go SDK for building Criteria adapters on protocol v2. Implement the Service interface and call adapterhost.Serve.

import "github.com/brokenbots/criteria-go-adapter-sdk/adapterhost"

func main() { adapterhost.Serve(&myAdapter{}) }

serve() handles the go-plugin handshake, the v2 RPCs, and --emit-manifest (emits adapter.yaml from the adapter's Info). Wire types come from the versioned criteria-adapter-proto module.

Running as a remote adapter

By default an adapter is launched locally by the Criteria host. An adapter can instead run anywhere (Kubernetes, ECS, a VM, a systemd unit) and dial out to the host's remote environment shim. Call adapterhost.ServeRemote instead of adapterhost.Serve; the Service implementation is identical.

package main

import (
	"os"

	"github.com/brokenbots/criteria-go-adapter-sdk/adapterhost"
)

func main() {
	tlsConf, err := adapterhost.LoadClientTLS(
		os.Getenv("CRITERIA_REMOTE_TLS_CERT"),
		os.Getenv("CRITERIA_REMOTE_TLS_KEY"),
		os.Getenv("CRITERIA_REMOTE_CA"),
	)
	if err != nil {
		panic(err)
	}
	if err := adapterhost.ServeRemote(&myAdapter{}, &adapterhost.ServeRemoteOptions{
		// host:port of the workflow's `remote` environment listen_address.
		Host:        os.Getenv("CRITERIA_REMOTE_HOST"),
		TLSConfig:   tlsConf,
		AcceptToken: os.Getenv("CRITERIA_REMOTE_TOKEN"),
		Identity: adapterhost.RemoteIdentity{
			Name:    "my-adapter",
			Version: "1.0.0",
			// The host verifies this digest against its lockfile entry.
			Digest: os.Getenv("CRITERIA_REMOTE_DIGEST"),
		},
		// Redial with backoff when the host connection drops.
		Reconnect: true,
	}); err != nil {
		panic(err)
	}
}

ServeRemote opens a (m)TLS connection to the host, sends a single newline-terminated identity frame ({name, version, digest, token}), then serves the gRPC AdapterService over the held connection. The host shim bridges that connection to a local socket and consumes it as if the adapter were local. With Reconnect: false (the default) it serves a single connection and returns; with Reconnect: true it redials with exponential backoff.

Deployment examples — copy-pasteable Kubernetes Deployment, docker-compose, and systemd manifests live under examples/remote/. Adapter launch and network reachability (VPN, Tailscale, ngrok, a public address) are the operator's responsibility; Criteria does not start or tunnel to remote adapters.

Status

Extracted from the in-tree sdk/adapterhost. Builds and tests standalone against criteria-adapter-proto. The criteria host still uses its in-tree copy; the switchover (host depends on this module + the proto module, in-tree sdk/ deleted) is a tracked follow-up — see RECONCILE.md. Versioned to track the criteria release line.

SDK design principles

Protocol-level liveness and stream lifetime are the SDK's responsibility, not the adapter author's. The most obvious implementation of any adapter method must never produce an adapter that silently breaks the host. For example, the SDK keeps the per-session log stream and its heartbeat running for as long as the host holds the stream open, regardless of whether the adapter's Log method blocks or returns early. This principle applies across all Criteria SDKs (Go, TypeScript, Python, and any future ones).

Security & dependencies

Supply-chain controls and the dependency-freshness policy are documented in SECURITY.md and docs/dependency-policy.md. Reproduce the CI security checks locally:

make vuln-scan      # osv-scanner — blocking known-vulnerability gate (WS49)
make deps-outdated  # go-mod-outdated — freshness report (WS50)
make deps-majors    # gomajor — available major (/vN) upgrades