Skip to content

WIT (act:core, act:tools, act:sessions)

The WIT is the source of truth for the protocol. JSON Schema, OpenAPI, and MCP shapes are derived from it. Three normative packages live in actcore/act-spec/wit/:

PackageStatusWhat’s in it
act:[email protected]NormativeCross-cutting types: cbor, metadata, error, localized-string
act:[email protected]NormativeThe tool data model plus the tool-provider interface — every component exports it
act:[email protected]Normative, opt-insession-provider — stateful components only
act:[email protected]Normative, opt-inCredential store. A host import: the host implements it, the component imports it
act:[email protected]Normative, opt-in, unimplementedconsent-authority — a component asks the host to authorize a semantic action
act:[email protected]Compatibility tierSync mirror of tool-provider, for toolchains whose async/stream codegen isn’t ready
act:[email protected]Compatibility tierSync mirror of session-provider
act:[email protected]Informative / RFCevent-provider (pub/sub)
act:[email protected]Informative / RFCresource-provider

Component-level metadata (name, version, description, capabilities) lives in the act:component WASM custom section, not as a WIT export.

package act:core@0.4.0;
interface types {
/// CBOR-encoded byte string (RFC 8949 §4.2 dCBOR when crossing host boundaries).
type cbor = list<u8>;
/// Key-value metadata. Keys are namespaced (`std:*`, `acme:*`, …),
/// values are CBOR-encoded.
type metadata = list<tuple<string, cbor>>;
variant localized-string {
plain(string),
localized(list<tuple<string, string>>),
}
/// Structured error. Well-known kinds: std:not-found, std:invalid-args,
/// std:timeout, std:capability-denied, std:internal, std:session-not-found.
record error {
kind: string,
message: localized-string,
metadata: metadata,
}
}

The data model lives in its own types interface, deliberately free of functions and of the stream<>-bearing tool-result. That split is the whole point of the 0.2.0 bump: a sync-shim adapter, or a generator whose async codegen is immature, can use act:tools/types without pulling in the async signatures.

package act:tools@0.2.0;
interface types {
use act:core/types@0.4.0.{localized-string, metadata, error};
record tool-definition {
name: string,
description: localized-string,
/// JSON Schema (hosts MAY also accept JSON Structure, detected via `$schema`).
parameters-schema: string,
metadata: metadata,
}
record content-part {
data: list<u8>,
mime-type: option<string>,
metadata: metadata,
}
/// `error` is terminal — no further events follow.
variant tool-event {
content(content-part),
error(error),
}
record list-tools-response {
metadata: metadata,
tools: list<tool-definition>,
}
}
interface tool-provider {
use act:core/types@0.4.0.{cbor, metadata, error};
use types.{tool-event, list-tools-response};
/// The only type in the package carrying a `stream<>`, which is why it
/// lives here rather than in `types`.
variant tool-result {
immediate(list<tool-event>),
streaming(stream<tool-event>),
}
list-tools: async func(metadata: metadata) -> result<list-tools-response, error>;
call-tool: async func(name: string, arguments: cbor, metadata: metadata) -> tool-result;
}

Both variants have identical observable semantics — an ordered sequence of tool-events, with tool-event::error terminal. Hosts and intermediaries MAY freely convert between them.

  • immediate(list<tool-event>) — natural for sync guest bodies and languages without an async runtime; the whole event list is materialized on return.
  • streaming(stream<tool-event>) — natural for long-running or I/O-bound tools; events flow as they’re produced.

Stateful components — bridges, REPLs, DB connections, browser automation — additionally export session-provider. Agents address per-session state via std:session-id metadata on subsequent tool-provider calls. See ACT-SESSIONS.

package act:sessions@0.2.0;
interface types {
use act:core/types@0.4.0.{metadata};
record session {
id: string,
metadata: metadata,
}
}
interface session-provider {
use act:core/types@0.4.0.{metadata, error};
use types.{session};
/// JSON Schema for valid `args` to open-session.
get-open-session-args-schema: async func(metadata: metadata)
-> result<string, error>;
/// Open a new session. `args` carries connection params and credentials
/// (per ACT-AUTH, auth lives in session args, not metadata).
open-session: async func(args: metadata, metadata: metadata)
-> result<session, error>;
/// Polite shutdown — sync, swallows errors. Hosts MUST call this for
/// every session they opened, before component deinit.
close-session: func(session-id: string);
}
  • Arguments and content bytes are CBOR by default — deterministic per RFC 8949 §4.2.
  • MIME-typed content parts may carry JSON, text, images, or opaque bytes — the host routes based on mime-type.
  • Metadata keys are namespaced strings. Values are CBOR-encoded.

Not part of the WIT — defined in the ACT specification. The host reads it without instantiating the component. See Manifest reference for the authoring side.