47 releases
Uses new Rust 2024
| new 0.4.93 | Feb 12, 2026 |
|---|---|
| 0.4.92 | Feb 12, 2026 |
| 0.4.79 | Jan 28, 2026 |
| 0.4.70 | Dec 31, 2025 |
| 0.4.47 | Nov 29, 2025 |
#114 in FFI
2,568 downloads per month
Used in 32 crates
(4 directly)
89KB
2K
SLoC
Greentic Interfaces Workspace
This repository contains the shared ABI contracts and Wasmtime runtime helpers used across the Greentic platform.
New v1 WIT surfaces for the unified flow/pack model live under
greentic:common-types@0.1.0,greentic:component-v1@0.1.0, andgreentic:pack-export-v1@0.1.0. The generic component ABI is now provided bycomponent@0.5.0(config-awareconfigrecord + optional JSON Schema export);component@0.4.0and the legacy pack worlds (pack-export@0.4.0,pack-export@0.2.0) remain for back-compat.
- Host/guest reexports:
greentic-interfaces-hostandgreentic-interfaces-guestnow surface the v1 worlds plus mapper helpers: component outcomes (ComponentOutcome,ComponentOutcomeStatus) and pack/flow descriptors (PackDescriptor,FlowDescriptor) for the new pack-export-v1 ABI.
Component config shape
greentic:component@0.5.0defines a canonical@configrecord inside thenodeinterface. Doc comments become JSON Schema descriptions,option<T>marks optional properties,@default(...)carries defaults, and@flow:hiddenmaps to anx_flow_hiddenextension.- Components can optionally export the
component-configurableworld (get-config-schema() -> string) to supply a JSON Schema directly; tooling still infers schemas from theconfigrecord by default. - Example WIT shape used by
component@0.5.0:
/// Configuration for this component.
/// Tooling will map this record to JSON Schema.
/// @config
record config {
/// Human-friendly title presented in UIs.
title: string,
/// Optional description used in documentation or previews.
description: option<string>,
/// Layout hint for hosts rendering collections.
/// @default("stacked")
layout: display-mode,
/// Maximum items to emit before truncating results.
/// @default(10)
max-items: u32,
/// Connection identifier propagated by flows but hidden from user config.
/// @flow:hidden
connection-id: option<string>,
}
Feature flags for the new v1 worlds
-
common-types-v0-1: enablesgreentic:common-types@0.1.0. -
component-v1: enablesgreentic:component-v1@0.1.0(component-host world) and reexports the component outcome mappers. -
pack-export-v1: enablesgreentic:pack-export-v1@0.1.0(pack-host world) and reexports the pack/flow descriptor mappers. -
Default and
wit-allnow include these flags; guest builds also stage the v1 WIT packages when the features are on. -
crates/greentic-interfacesexposes the WebAssembly Interface Types (WIT) packages, generated Rust bindings, and thin mappers that bridge the generated types to the richer structures ingreentic-types. It is intentionally ABI-only and has no Wasmtime dependency. -
crates/greentic-interfaces-hostcurates the host-facing bindings: Wasmtime-ready WIT worlds plus the shared mappers. -
crates/greentic-interfaces-guestcurates the guest-facing bindings for components built againstwasm32-wasip2, including distributor API import bindings plusDistributorApiImports(distributor-api-imports) andDistributorApiImportsV1_1(distributor-api-v1-1-imports) for resolve/get/get-v2/warm and ref-based resolution + digest fetches. -
crates/greentic-interfaces-wasmtimehosts the Wasmtime integration layer. It wires the Greentic host imports into a Wasmtime linker, instantiates components, and forwards calls through the ABI bindings.
Node configuration schemas always live alongside their components. This repository only ships shared WIT contracts plus the corresponding bindings/mappers.
Provider protocols are now unified under greentic:provider-schema-core@1.0.0. Legacy messaging/events/secrets provider WIT worlds have been removed; migrate provider components to provider-core JSON schemas instead of typed provider-specific worlds.
These crates are published from this workspace. Downstream components that only need the ABI can depend solely on greentic-interfaces. Runtimes that execute packs should add greentic-interfaces-wasmtime and choose whether to stay on the stable Wasmtime feature path or opt into the nightly configuration. Hosts that just want re-exported bindings can depend on greentic-interfaces-host, while guest components can pull greentic-interfaces-guest for wasm32-wasip2 builds.
// Host side: wire imports into a Wasmtime linker.
use greentic_interfaces_host::host_import::v0_6::add_to_linker;
// Guest side: call host capabilities from inside a component.
use greentic_interfaces_guest::component::node::Guest;
use greentic_interfaces_guest::secrets_store::secrets_store;
Which crate should I use?
- Hosts (runner, deployer, gateways):
greentic-interfaces-host - Wasm components (
wasm32-wasip2):greentic-interfaces-guest - Wasmtime glue / linker helpers:
greentic-interfaces-wasmtime - ABI/WIT tooling and validation:
greentic-interfaces
For debugging wkg resolution with fully staged dependencies, use
scripts/wkg-build-staged.sh (defaults to attestation@1.0.0).
Host examples
use greentic_interfaces_host::http::http_client;
use greentic_interfaces_host::secrets::store_v1::secrets_store;
use greentic_interfaces_host::telemetry::log;
Guest examples
use greentic_interfaces_guest::component::node::Guest;
use greentic_interfaces_guest::secrets_store::secrets_store;
use greentic_interfaces_guest::http_client::http_client;
use greentic_interfaces_guest::telemetry_logger::logger_api;
// Distributor imports (host calls) — enable the feature in Cargo.toml:
// greentic-interfaces-guest = { version = "0.4", features = ["distributor-api-imports"] }
use greentic_interfaces_guest::distributor_api::DistributorApiImports;
use greentic_interfaces_guest::distributor_api::ResolveComponentRequest;
let api = DistributorApiImports::new();
let _resp = api.resolve_component(&ResolveComponentRequest {
tenant_id: "tenant".into(),
environment_id: "env".into(),
pack_id: "pack".into(),
component_id: "comp".into(),
version: "1.0.0".into(),
extra: "{}".into(),
});
// Ref-based distributor imports (host calls) — enable the feature in Cargo.toml:
// greentic-interfaces-guest = { version = "0.4", features = ["distributor-api-v1-1-imports"] }
use greentic_interfaces_guest::distributor_api_v1_1::DistributorApiImportsV1_1;
let ref_api = DistributorApiImportsV1_1::new();
let resolved = ref_api.resolve_ref("oci://registry.example/greentic/component@sha256:...");
let _artifact = ref_api.get_by_digest(&resolved.digest);
Minimal guest component (2 funcs + macro)
Use the component_entrypoint! macro so the crate generates the WASM export glue (marker section, unsafe #[export_name] funcs) for you. Only the payload description and invoke handler are required; streaming defaults to [Progress(0), Data(result), Done] and lifecycle hooks default to Ok.
#![cfg_attr(not(target_arch = "wasm32"), allow(dead_code))]
use greentic_interfaces_guest::component::node::{InvokeResult, NodeError};
use greentic_interfaces_guest::component_entrypoint;
fn describe_payload() -> String {
r#"{"name":"demo","version":"1.0.0"}"#.to_string()
}
fn handle_message(op: String, input: String) -> InvokeResult {
match op.as_str() {
"fail" => InvokeResult::Err(NodeError {
code: "demo".into(),
message: format!("bad input: {input}"),
retryable: false,
backoff_ms: None,
details: None,
}),
_ => InvokeResult::Ok(format!("ok:{input}")),
}
}
component_entrypoint!({
manifest: describe_payload,
invoke: handle_message,
// Optional:
// invoke_stream: true, // default; set false to disable
// on_start: my_start_fn,
// on_stop: my_stop_fn,
});
Migration guide: move to host/guest crates
- Replace direct
greentic-interfacesimports in hosts withgreentic-interfaces-hostand switch to the curated modules (secrets,state,http,telemetry,oauth). - Replace direct bindgen usage in wasm components with
greentic-interfaces-guest; import from the module for the capability you need (secrets_store,state_store,http_client,oauth). - Update your target/toolchain: guests should build with
--target wasm32-wasip2; hosts stay native. - For Wasmtime wiring, depend on
greentic-interfaces-wasmtimealongside the host crate if you need linker helpers. - Drop local WIT regeneration: the host/guest crates ship the generated bindings; WIT remains the source of truth here.
For local development you can override the crates.io dependency on greentic-types by copying .cargo/local-patch.example.toml to .cargo/config.toml and pointing it at a sibling checkout of greentic-types.
Feature flags
| Feature | World(s) enabled | Published package | Notes |
|---|---|---|---|
secrets-store-v1 |
greentic:secrets-store/store@1.0.0 (store) |
package.wit |
Read-only secret lookup (get) returning bytes with structured errors. |
state-store-v1 |
greentic:state/store@1.0.0 (store) |
package.wit |
Tenant-scoped blob store aligned with HostCapabilities.state. |
http-client-v1 |
greentic:http/client@1.0.0 (client) |
package.wit |
Preview 2 HTTP client matching HostCapabilities.http. |
http-client-v1-1 |
greentic:http/client@1.1.0 (client) |
package.wit |
Adds optional request-options + tenant context; hosts should also expose @1.0.0 for legacy bundles. |
telemetry-logger-v1 |
greentic:telemetry/logger@1.0.0 (logger) |
package.wit |
Tenant-aware telemetry logger aligned with HostCapabilities.telemetry. |
worker-api |
greentic:worker/worker@1.0.0 (worker) |
package.wit |
Generic worker request/response envelope; see docs/worker.md for details. |
gui-fragment |
greentic:gui/gui-fragment@1.0.0 (gui-fragment) |
package.wit |
Server-rendered HTML fragments for Greentic-GUI; hosts call render-fragment(fragment-id, ctx) and inject the returned HTML. |
oauth-broker-v1 |
greentic:oauth-broker@1.0.0 (broker, broker-client) |
package.wit |
Generic OAuth broker: hosts implement the broker world; guest components import via the new broker-client world to build consent URLs, exchange codes, and fetch tokens. |
component-v0-5 |
greentic:component/component@0.5.0 (component, component-configurable) |
package.wit |
Config-aware component ABI with a canonical @config record; optional get-config-schema() export for JSON Schema overrides; component@0.4.0 remains available for legacy consumers. |
describe-v1 |
greentic:component@1.0.0 (describe-v1) |
package.wit |
Describe-only schema export for packs without the full component ABI. |
runner-host-v1 |
greentic:host@1.0.0 (http-v1, kv-v1) |
package.wit |
Legacy runner host bundle (now secrets-free; kept only for HTTP/KV). |
component-lifecycle-v1 |
greentic:lifecycle@1.0.0 (lifecycle-v1) |
package.wit |
Optional lifecycle hooks (init, health, shutdown). |
source-v1 |
greentic:source/source-sync@1.0.0 |
package.wit |
Tenant-scoped source provider interface (list repos/branches, commit metadata, webhooks). |
build-v1 |
greentic:build/builder@1.0.0 |
package.wit |
Tenant-scoped build execution (build plan/status/log refs). |
scan-v1 |
greentic:scan/scanner@1.0.0 |
package.wit |
Tenant-scoped scan execution (scan kind/result/SBOM refs). |
signing-v1 |
greentic:signing/signer@1.0.0 |
package.wit |
Tenant-scoped signing/verification using signing key refs. |
attestation-v1 |
greentic:attestation/attester@1.0.0 |
package.wit |
Tenant-scoped attestation generation (predicate/statement refs). |
policy-v1 |
greentic:policy/policy-evaluator@1.0.0 |
package.wit |
Tenant-scoped policy evaluation (allow/deny with reasons). |
metadata-v1 |
greentic:metadata/metadata-store@1.0.0 |
package.wit |
Tenant-scoped metadata upsert/query for components/versions. |
distributor-api |
greentic:distributor-api/distributor-api@1.0.0 |
package.wit |
Active distributor API for runner/deployer flows: resolve-component (includes secret requirements), legacy get-pack-status string, structured get-pack-status-v2 (status + secret requirements), and warm-pack; guests can also enable distributor-api-imports for import bindings plus a DistributorApiImports helper. |
distributor-api-v1-1 |
greentic:distributor-api/distributor-api@1.1.0 |
package.wit |
Adds ref-based resolution (resolve-ref) and digest fetching (get-by-digest) for OCI component references (tag or digest); keep @1.0.0 for pack-id + component-id flows. |
distribution-v1 |
greentic:distribution/distribution@1.0.0 |
package.wit |
Experimental desired state submission/retrieval (tenant + IDs + JSON blobs), not used by current flows. |
oci-v1 |
greentic:oci/oci-distribution@1.0.0 |
package.wit |
Tenant-scoped OCI distribution helpers (push/get pull reference). |
wit-all |
Aggregates every feature above plus the legacy defaults (component-v0-4, types-core-*, etc.) |
– | Handy opt-in when you just want “everything on”. |
Additional shared package: provider:common@0.0.2 (under wit/provider-common/world.wit) carries messaging provider metadata, capability flags, limits, render tiers, warnings, and encoded payload helpers for provider components. Enable the provider-common feature to generate bindings; the package remains additive and shared across messaging providers.
Distributor component references (v1.1)
Packs and runners that need to resolve remote components should use the ref-based distributor surface in greentic:distributor-api@1.1.0:
- pass a ComponentRef string (
oci://registry/repo:tagoroci://registry/repo@sha256:<digest>) intoresolve-ref. - read the returned digest + metadata and persist the digest alongside the pack manifest.
- fetch the actual artifact with
get-by-digest(returns bytes or a filesystem path).
Older flows that only have pack-id + component-id + version should keep using resolve-component from @1.0.0.
Host crate feature gates
greentic-interfaces-host exposes optional features for host bindings:
worker-v1: enablesgreentic_interfaces_host::worker::*forgreentic:worker@1.0.0.oauth-broker-v1: enablesgreentic_interfaces_host::oauth_broker::*forgreentic:oauth-broker@1.0.0; pair this withgreentic-oauth-sdkwhen calling the broker from services.
Example:
greentic-interfaces-host = { version = "0.4", features = ["worker-v1", "oauth-broker-v1"] }
Host quickstart (workers + broker):
use greentic_interfaces_host::{mappers, worker};
use greentic_types::TenantCtx;
use serde_json::json;
// Convert the shared TenantCtx into the WIT shape expected by worker bindings.
let wit_ctx = mappers::tenant_ctx_to_wit(TenantCtx::default())?;
// Build a worker request using the host bindings.
let request = worker::exports::greentic::worker::worker_api::WorkerRequest {
version: "1.0".into(),
tenant: wit_ctx,
worker_id: "example-worker".into(),
correlation_id: None,
session_id: None,
thread_id: None,
payload_json: "{}".into(),
timestamp_utc: "2025-01-01T00:00:00Z".into(),
};
// Reverse mapping when you need to turn a WIT tenant back into greentic_types::TenantCtx:
let tenant_ctx = mappers::tenant_ctx_from_wit(request.tenant.clone())?;
// OAuth broker bindings live under:
// greentic_interfaces_host::oauth_broker::exports::greentic::oauth_broker::broker_v1
// Host-friendly worker request/response with serde_json payloads:
use greentic_interfaces_host::worker::{HostWorkerRequest, HostWorkerResponse};
let host_req = HostWorkerRequest {
version: "1.0".into(),
tenant: TenantCtx::default(),
worker_id: "my-worker".into(),
payload: json!({"input": "value"}),
timestamp_utc: "2025-01-01T00:00:00Z".into(),
correlation_id: None,
session_id: None,
thread_id: None,
};
// Convert to WIT and invoke via generated bindings (e.g., Wasmtime host):
let wit_req = greentic_interfaces_host::worker::exports::greentic::worker::worker_api::WorkerRequest::try_from(host_req)?;
// Convert responses back to host types:
let host_resp: HostWorkerResponse = wit_resp.try_into()?;
MCP router WIT
All MCP protocol WIT packages live here; routers should not redefine them elsewhere. New work should target wasix:mcp@25.06.18; older snapshots remain only for compatibility.
| WIT package | MCP spec revision | Link |
|---|---|---|
wasix:mcp@24.11.05 |
2024-11-05 (+ Greentic config/secret/output descriptors) | https://modelcontextprotocol.io/specification/2024-11-05 |
wasix:mcp@25.03.26 |
2025-03-26 (annotations, audio content, completions, progress; metadata carries config/secrets/output hints) | https://modelcontextprotocol.io/specification/2025-03-26 |
wasix:mcp@25.06.18 |
2025-06-18 (structured output, resource/resource-link, elicitation, titles/_meta, tightened auth/resource metadata) | https://modelcontextprotocol.io/specification/2025-06-18 |
Deployment plan world
Deployment packs can import greentic:deploy-plan@1.0.0 to read the current DeploymentPlan and emit status updates. The world exposes two funcs:
get-deployment-plan()– returns the JSON-encodedDeploymentPlanbuilt by the host/deployer for this execution.emit-status(message)– reports a free-form status line that hosts may log or display in a UI.
Hosts wire this world alongside the existing runner-host imports, so deployment flows still run as ordinary events flows with an additional channel for structured deployment context.
Minimum Supported Rust Version
The workspace targets Rust 1.88 or newer (required by the 2024 edition). CI pins the same stable toolchain for formatting/clippy, so make sure your local toolchain matches 1.88+ when hacking.
Examples
Two smoke-level examples live under examples/:
component-describe: ano_stdcomponent that implementsdescribe-v1::describe-json.runner-host-smoke: a host-side binary that links the runner-host imports, instantiates thecomponent-describeWasm artifact, and executesdescribe-json. The runner repository also ships a secrets-oriented guest fixture (component-secrets) that exercises thesecrets-storeimports end-to-end.
Running the examples locally
# Install the WASI Preview 2 target once (matches CI)
rustup target add wasm32-wasip2 --toolchain 1.88.0
# Compile the component to Wasm (targets wasm32-wasip2)
CARGO_TARGET_DIR=target cargo build --manifest-path examples/component-describe/Cargo.toml --target wasm32-wasip2
# Run the host smoke test (reuses the artifact above)
COMPONENT_DESCRIBE_WASM=target/wasm32-wasip2/debug/component_describe.wasm \
CARGO_TARGET_DIR=target cargo run --manifest-path examples/runner-host-smoke/Cargo.toml
What is greentic-interfaces-wasmtime?
The runtime crate provides Wasmtime glue for the Greentic WIT packages: an engine builder, feature-gated add_*_to_linker helpers, and mapper utilities that bridge between the ABI structs re-exported from greentic-interfaces and the richer models in greentic-types. It does not regenerate WIT on its own – everything flows through the ABI crate – so downstream consumers (runner, MCP, packs) can instantiate components and call exports without duplicating linker boilerplate.
Provenance
Every tagged release publishes a tarball, checksum, raw package.wit files, and a signed provenance note that enumerates per-package hashes. Grab the latest release notes to verify what you downloaded.
Local Checks
Run the CI-equivalent checks locally with:
ci/local_check.sh
Toggles:
LOCAL_CHECK_ONLINE=1– enable networked steps (none today, reserved for future use).LOCAL_CHECK_STRICT=1– fail immediately if required tools are missing.LOCAL_CHECK_VERBOSE=1– print every command before executing it.LOCAL_CHECK_EXAMPLES=1– build/run the example crates (requires thewasm32-wasip2target).- The example steps expect
rustup target add wasm32-wasip2 --toolchain 1.88.0to have been run first.
A pre-push hook is installed automatically (if absent) to run the script before pushing; remove .git/hooks/pre-push if you prefer to opt out.
Fetching WIT packages from OCI
The published WIT bundles live in GitHub Container Registry under ghcr.io/greentic-ai/wit. The registry metadata served from https://greentic.ai/.well-known/wasm-pkg/registry.json advertises this prefix, so any wkg client can resolve the greentic:* namespace automatically.
# 1. Install the wasm packaging CLI
cargo install wkg
# 2. Point your config at the Greentic registry (writes ~/.config/wasm-pkg/config.toml)
wkg config --default-registry greentic.ai
# 3. Fetch the desired package (auto-discovers ghcr.io/greentic-ai/wit/<namespace>/<pkg>)
wkg get greentic:component@1.0.0 --output ./component.wasm
# or grab the raw WIT:
wkg get greentic:component@1.0.0 --output ./component.wit --format wit
If you prefer to edit the config file manually, add this stanza:
[namespace_registries]
greentic = "greentic.ai"
With that mapping in place the CLI will transparently pull from GHCR using the namespace prefix advertised by the registry metadata (greentic-ai/wit/).
Legacy secrets provider surfaces are documented for migration notes in docs/secrets-provider.md; provider-core JSON schemas have replaced the typed provider WIT worlds.
Using secrets-store-v1 from guests
The secrets-store-v1 feature gates the greentic:secrets-store/store@1.0.0 package. Secret requirement metadata now lives in greentic:secrets-types@1.0.0 (key/scope/format/schema/examples); distributor responses surface secret-requirements using that shared type, and no secret values are returned.
Components that need to work with secrets should:
All secret requirement modeling is handled in greentic-types; greentic-interfaces only defines the WIT surface.
- Enable
secrets-store-v1(orwit-all) on the dependency. - Import the interface in their WIT (
use greentic:secrets-store/store@1.0.0) or viawit-bindgen. - Call the synchronous host function surfaced by the runner:
interface secrets-store {
/// Secret lookup failures.
enum secrets-error { not-found, denied, invalid-key, internal }
/// Fetch a secret by key; returns `none` when the key is missing.
get: func(key: string) -> result<option<list<u8>>, secrets-error>;
}
getreturnsSome(bytes)when the secret exists,Nonewhen absent, and a structuredsecrets-errorwhen the host rejects or cannot service the lookup.
Dependencies
~11–22MB
~455K SLoC