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/:
| Package | Status | What’s in it |
|---|---|---|
act:[email protected] | Normative | Cross-cutting types: cbor, metadata, error, localized-string |
act:[email protected] | Normative | The tool data model plus the tool-provider interface — every component exports it |
act:[email protected] | Normative, opt-in | session-provider — stateful components only |
act:[email protected] | Normative, opt-in | Credential store. A host import: the host implements it, the component imports it |
act:[email protected] | Normative, opt-in, unimplemented | consent-authority — a component asks the host to authorize a semantic action |
act:[email protected] | Compatibility tier | Sync mirror of tool-provider, for toolchains whose async/stream codegen isn’t ready |
act:[email protected] | Compatibility tier | Sync mirror of session-provider |
act:[email protected] | Informative / RFC | event-provider (pub/sub) |
act:[email protected] | Informative / RFC | resource-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, }}act:[email protected] — types + tool-provider
Section titled “act:[email protected] — types + tool-provider”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;}tool-result variants
Section titled “tool-result variants”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.
act:[email protected] — session-provider (opt-in)
Section titled “act:[email protected] — session-provider (opt-in)”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);}Encoding
Section titled “Encoding”- 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.
Component metadata (CBOR custom section)
Section titled “Component metadata (CBOR custom section)”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.