Skip to main content
Verified against aomi-sdk@08b21f9 on 2026-06-29.
The Aomi SDK is a Rust crate for building Apps. An App is a dynamic plugin that the Aomi runtime hot loads at runtime as a shared library (cdylib) over a stable C ABI. You write typed tools in Rust, compile to a .so (Linux) or .dylib (macOS), and the runtime loads it without a restart.
This is the public plugin surface. You build against the aomi-sdk crate, and your tools cross the FFI boundary as JSON. The runtime and loader are not part of this crate, so you never link against host internals. The compatibility gate is the SDK version: the host and your plugin must build against the same aomi-sdk version.

The four pieces

A minimal App needs four things:
1

An app struct

A marker type that ties everything together. It must be Clone + Default + Send + Sync + 'static. A unit struct works well.
2

A typed args struct

Deserialized from the incoming JSON. Derive Deserialize and JsonSchema. The doc comments on each field are model facing: they become the parameter schema the LLM reads when it picks your tool.
3

A tool implementation

A struct that implements DynAomiTool. This is your actual logic.
4

The dyn_aomi_app! macro

This generates the manifest, the dispatch router, and the FFI exports the host calls. You never write the C ABI by hand.

Cargo.toml

The crate must build as a cdylib, and it depends on aomi-sdk.
Pin aomi-sdk exactly (=3.0.3), not with a caret range. The runtime gates plugin loading on an exact SDK version match, so the pin must equal the platform’s required_sdk_version (see platform.json in the platform repo). A mismatch fails before your App ever loads.
Pin the platform requirement, not the crate’s own version. The aomi-sdk crate ships at 3.0.4, but the community platform requires =3.0.3. Match platform.json’s required_sdk_version, today =3.0.3, not the crate’s latest.
aomi-sdk exports schemars and serde_json again from inside itself, so your tool code can reach them through the crate (for example aomi_sdk::schemars::JsonSchema) without managing version alignment yourself.

The DynAomiTool trait

Every tool is one struct that implements DynAomiTool. The trait carries two associated types, three consts, and the run methods.
The runtime auto generates each tool’s parameter schema from Args using JsonSchema. You do not write JSON Schema by hand.
Prefer intent shaped names like search_*, get_*, build_*, and submit_* over raw endpoint wraps. Keep the set small. Three to eight tools per App is typical for a clean workflow.

The tool context

Every run call receives a DynToolCallCtx. It is a small projection of the host context with only what your tool needs.
You can read nested host attributes by path with helper methods:

Async tools

For long running or streaming work, set IS_ASYNC = true and implement run_async instead of run. The host polls for updates through the DynAsyncSink. You push intermediate values with emit, signal the terminal result with complete, report a failure with fail, and check for host cancellation with is_canceled.
Intermediate emit updates must be bare values. The terminal complete call is the only place that accepts a routed return. There is no terminal anchor for routing mid stream, so the SDK rejects routed envelopes passed to emit.

The dyn_aomi_app! macro

dyn_aomi_app! is the one macro you call per App. It wires your tools into a dispatch router, builds the plugin manifest the host reads, and generates the FFI exports the runtime calls across the C ABI. You do not implement DynAomiApp or any C function by hand.

Secrets

If your App needs external credentials, declare them as Secret slots. Each slot has a canonical name in SCREAMING_SNAKE_CASE, a one sentence description shown in the settings UI, and a required flag.
The host reads the declared slots from your manifest. When a slot is required: true, the host gates App load on the user having filled that slot in the runtime secret vault. At tool call time the host pre resolves the slots and injects the raw values into ctx.secrets. Your tool reads them with resolve_secret_value, which never logs, persists, or echoes the value to the model. resolve_secret_value checks three sources in order and returns your missing_message if none resolve:
1

Explicit argument

The value the caller passed in, if any.
2

Injected vault secret

ctx.secrets[name], injected by the host from the per App vault.
3

Environment variable

A fallback name env var, used by the CLI and tests where no vault is in scope.

Host namespaces

The namespaces field lists host side capability sets the runtime injects alongside your own tools. The default is ["evm-core"], which most Apps want for EVM wallet flows.

How the runtime hot loads your plugin

You ship a compiled .so or .dylib. The runtime does the rest. It calls the generated FFI exports across the C ABI, reads your manifest, validates the SDK version, and serves tool calls. When a new build arrives, the runtime swaps it in atomically. All data crosses the boundary as JSON serialized C strings. Active chat sessions keep the old plugin while new sessions pick up the new one, so a reload needs no restart.

Testing your tools

The aomi_sdk::testing module lets you unit test tools without loading the full FFI plugin. Build a context with TestCtxBuilder, then call run_tool for sync tools or run_async_tool for streaming tools.
TestCtxBuilder also lets you seed state attributes with .attribute(...) and inject a resolved secret with .secret(...), so you can simulate exactly what the host would pass.
run_async_tool returns (updates, terminal): every non terminal emit value in order, plus the terminal complete payload.

A full example, start to finish

A minimal greeter App, straight from the crate docs:
The reference template at sdk/examples/app-template-http in the aomi-labs/aomi-sdk repo shows the recommended file split for a real App: src/lib.rs for the manifest and preamble, src/client.rs for the HTTP client and typed args, and src/tool.rs for the tool implementations.

Next steps

Building an App

The full workflow for authoring, structuring, and publishing an App.

CLI toolchain

aomi-build to scaffold, compile, and deploy plugins, and aomi-run to exercise them locally.
Last modified on July 27, 2026