// WIT contract for grain WASM plugins (Component Model).
//
// Plugins implement the `grain-plugin` world: they export `plugin`,
// which provides `init`, `list-tools`, and `call-tool`. The host
// provides logging, env-var access, and HTTP primitives — each
// gated by the plugin's declared capabilities in `plugin.toml`.
package grain:plugin;
/// Host-provided functions imported by the plugin.
interface host {
/// Log severity levels.
enum log-level {
debug,
info,
warn,
error,
}
/// HTTP response returned by host HTTP functions.
record http-response {
status: u16,
headers: list<tuple<string, string>>,
body: string,
}
/// Emit a log line at the given severity.
log: func(level: log-level, msg: string);
/// Read an environment variable. Returns `none` when unset.
env-get: func(key: string) -> option<string>;
/// HTTP GET. Returns an error string on transport failure.
http-get: func(url: string, headers: list<tuple<string, string>>)
-> result<http-response, string>;
/// HTTP POST. Returns an error string on transport failure.
http-post: func(url: string, headers: list<tuple<string, string>>, body: string)
-> result<http-response, string>;
}
/// Plugin-exported interface.
interface plugin {
/// Describes one tool the plugin provides.
record tool-def {
/// Unique tool name (snake_case by convention).
name: string,
/// Human-readable label shown in the UI.
label: string,
/// One-paragraph description for the LLM.
description: string,
/// JSON Schema string describing the tool's parameters.
parameters-json: string,
}
/// Result returned from a tool invocation.
record tool-result {
/// JSON-encoded content value.
content-json: string,
/// Whether this result represents an error.
is-error: bool,
}
/// Metadata returned by `init`.
record plugin-info {
/// Human-readable plugin name.
name: string,
/// SemVer version string.
version: string,
}
/// Called once after instantiation. Returns plugin metadata or
/// an error string that aborts loading.
init: func() -> result<plugin-info, string>;
/// Enumerate all tools the plugin provides.
list-tools: func() -> list<tool-def>;
/// Invoke a tool by name with JSON-encoded arguments.
call-tool: func(name: string, args-json: string) -> tool-result;
}
/// Optional orchestration surface for plugins that want to declare
/// model-role slots and participate in host-controlled lifecycle hooks.
///
/// Compatibility note: this interface is exported only by the v2 world
/// below. The original `grain-plugin` world intentionally stays unchanged
/// so existing plugins keep loading without recompilation.
interface orchestration {
/// Lifecycle points a plugin may observe. The host owns when these
/// hooks are called and validates every returned action before applying it.
enum hook-point {
before-agent-start,
after-tool-call,
prepare-next-turn,
should-stop-after-turn,
}
/// One model-role slot declared by the plugin.
record role-def {
/// Stable role name, e.g. "designer" or "coder".
name: string,
/// grain-llm-models model id, e.g. "openai/gpt-4o".
model: string,
/// System prompt text or a host-understood prompt key.
prompt: string,
/// Tool names allowed while this role is active.
tools: list<string>,
/// Optional thinking level string: off/minimal/low/medium/high/xhigh.
thinking-level: option<string>,
}
/// One hook subscription declared by the plugin.
record hook-def {
point: hook-point,
/// Human-readable hook name for diagnostics.
name: string,
}
/// Optional UI header override. The host decides which surfaces honor
/// this; terminal UIs use it for the provider/model header.
record ui-header {
provider: option<string>,
model: option<string>,
}
/// Host action requested by a hook. The host treats these as intent,
/// not authority: model ids, roles, tools, and timing are validated
/// outside the guest before any agent state changes.
variant host-action {
switch-role(string),
switch-model(string),
set-system-prompt(string),
set-active-tools(list<string>),
inject-user-message(string),
stop-after-turn(bool),
emit-custom(string),
set-ui-header(ui-header),
set-ui-status(string),
}
/// Enumerate model-role slots this plugin contributes.
list-roles: func() -> list<role-def>;
/// Enumerate lifecycle hooks this plugin wants called.
list-hooks: func() -> list<hook-def>;
/// Invoke one hook with a JSON-encoded context payload. Returns a list
/// of requested host actions.
call-hook: func(point: hook-point, context-json: string)
-> result<list<host-action>, string>;
}
/// The world a grain plugin must target.
world grain-plugin {
import host;
export plugin;
}
/// Extended world for orchestration-aware plugins. This is deliberately
/// separate from `grain-plugin` so v1 plugins are not forced to export the
/// orchestration interface.
world grain-plugin-v2 {
import host;
export plugin;
export orchestration;
}