Six doors into the same pipeline
Client CLI
The client CLI
The aomi command ships inside the @aomi-labs/client npm package. It talks to a running Aomi backend (https://chat.aomi.dev by default), keeps a session across runs, stages transactions, simulates them, and signs locally. Humans and coding agents use the same commands. This is the client CLI, not the builder toolchain; that is aomi-build.
Install and verify
npm install -g @aomi-labs/client
aomi --version
aomi account login # browser device auth, binds sessions to your account
aomi --prompt "what is the price of ETH?"Run once without installing with npx @aomi-labs/client --help. Run aomi with no arguments for the interactive REPL, with slash commands like /app, /model and /key.
The transaction loop
aomi chat "swap 1 ETH for USDC" --new-session --public-key 0xYourAddress --chain 1
aomi tx list # pending and signed, shows tx-1, tx-2 ...
aomi tx simulate tx-1 tx-2 # rehearse the batch on a fork
aomi tx sign tx-1 tx-2 # sign locally and submitEVM and Solana requests have separate ID spaces. If both have a tx-1, the list shows evm:tx-1 and svm:tx-1 and aomi tx sign needs the qualified form.
Wallets and keys
aomi wallet set 0xYourPrivateKey # EVM, saved with file mode 0600 under ~/.aomi
aomi wallet set --solana 5Kd3N...base58... --cluster devnet
aomi wallet current
aomi account login --wallet # SIWE with the configured EVM key, no browserThe key never leaves your machine because signing is local. To avoid persisting it, pass --private-key per command or set PRIVATE_KEY in the environment.
Everything else
Flags all have an environment variable twin: AOMI_BACKEND_URL, AOMI_API_KEY, AOMI_APP, AOMI_MODEL, AOMI_CHAIN_ID, AOMI_PUBLIC_KEY, AOMI_STATE_DIR (default ~/.aomi), and AOMI_AA_MODE (4337 or 7702). Do not set AOMI_AA_MODE for Arc. Account abstraction is not available there.
Agent Skills
Agent Skills
An Aomi Skill is a markdown file that teaches an AI coding assistant how to use Aomi. Nothing to compile. The agent reads the skill, learns the command surface and the operating procedure, and drives the aomi CLI on your machine. Skills follow the Agent Skills spec, so they work in Claude Code, Cursor, Codex CLI, Gemini CLI and any runtime that supports it.
npx skills add aomi-labs/skills # both skills at once
npm install -g @aomi-labs/client@latest # aomi-transact needs the CLI and Node 18+
aomi account loginThen ask in plain English. The agent picks the skill from what you ask: transaction prompts route to aomi-transact, scaffolding prompts to aomi-build. For a swap it runs a fresh thread, aomi tx list, aomi tx simulate, then aomi tx sign only for the request you asked for.
The safety model, in the skill's own manifest
- Shell allowlist. Only aomi and npx @aomi-labs/client@latest may execute.
- Network allowlist. Outbound traffic is restricted to Aomi's API.
- File scope. Reads and writes limited to ~/.aomi/. Writes to agent identity files are denied.
- No blind signing. Multi-step flows go through aomi tx simulate before aomi tx sign, and the agent signs only a pending tx-N that aomi tx list has shown and you asked for.
- Opaque credentials. The skill never invents, derives or echoes a credential.
Drain vector guards run underneath: Aomi blocks calldata fields that can redirect funds when they do not match the signer, such as recipient on Uniswap, onBehalfOf on Aave, mintRecipient on CCTP and _to on OP Stack bridges. A batch that fails on one of these is the guard doing its job, and the skill surfaces the block to you instead of reformulating the prompt to get past it.
MCP
MCP, the other door for coding agents
Skills run on your machine with your key. MCP connects the same agents to Aomi's server, where actions are staged and approved on a wallet surface. Aomi exposes two Model Context Protocol resources over Streamable HTTP, with OAuth.
Connect Agent MCP
# Claude Code
claude mcp add --transport http aomi-agent https://chat.aomi.dev/v1/agent/mcp
# then run /mcp, select aomi-agent, and authenticate in the browser
# Codex
codex mcp add aomi-agent --url https://chat.aomi.dev/v1/agent/mcp
codex mcp login aomi-agent
// Cursor, in the MCP servers config
{ "mcpServers": { "aomi-agent": { "url": "https://chat.aomi.dev/v1/agent/mcp" } } }After authorization, ask your client: Ask Aomi for my USDC balance on Base, then explain the result.
Agent MCP tools
Supervising a turn
Call aomi_chat, keep the cursor it returns, poll aomi_check while the status is processing, and when a response includes a pending action send the user to the portal or an authenticated CLI to approve it. Do not report transaction success until a later check returns the confirmed result.
Pipeline MCP
codex mcp add aomi-pipeline --url https://chat.aomi.dev/v1/pipeline/mcp
codex mcp login aomi-pipelineBroad to narrow: read Agent context if needed, list Apps and namespaces, list the tools in a namespace and inspect their schemas, then call one tool with validated arguments. Current tools: aomi_get_agent_context, aomi_list_apps, aomi_list_namespaces, aomi_list_tools, aomi_call_tool. The client's tool list response is the final authority.
Authentication
The first unauthenticated request returns an OAuth challenge; your client uses PKCE and requests a token for the exact resource. Agent and Pipeline grants are separate, and signing authority is separate again: OAuth identifies the account, a linked wallet makes an address available, and every action still follows the wallet's review and signing policy. Private keys, seed phrases and reusable signatures never pass through MCP. Authorize only clients you trust.
Rust SDK
Build an App with the Rust SDK
An App is a small Rust crate: aomi.toml, Cargo.toml and src/lib.rs, with Cargo.lock committed. You need a current Rust toolchain and git. The platform still has to build and activate it before it is live.
Install the toolchain
Install the aomi-sdk crate from crates.io. The cli feature builds aomi-build. Add dev-runtime to also get aomi-run. There is no separate aomi-build package on crates.io or npm.
cargo install aomi-sdk --locked --features cli,dev-runtime
aomi-build deploy --help # there is no --version flagCreate the folder
The folder name is your slug. Use kebab case.
mkdir hello-aomi && cd hello-aomi && mkdir srcaomi.toml, who your App is and where it ships
[app]
name = "hello-aomi"
display_name = "Hello Aomi"
platform = "community"
git = "https://github.com/you/hello-aomi"
public = trueCargo.toml, pin the SDK exactly
The platform requires a specific aomi-sdk version and it moves often. Never copy a number from a doc. Run aomi-build sdk check for the live requirement, or aomi-build sdk fix to set it. Pin with a leading =, never ^.
[package]
name = "hello-aomi"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib"]
[dependencies]
aomi-sdk = "=X.Y.Z" # the version aomi-build sdk check reports
schemars = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"src/lib.rs, one tool and the macro that registers it
The DESCRIPTION is what the model reads to decide when to call your tool, so write it as a trigger. namespaces = [] means the App asks for no host powers like wallet signing; declare namespaces when it needs them.
use aomi_sdk::schemars::JsonSchema;
use aomi_sdk::*;
use serde::Deserialize;
use serde_json::{Value, json};
#[derive(Clone, Default)]
pub struct HelloApp;
#[derive(Debug, Deserialize, JsonSchema)]
pub struct GreetArgs {
/// The name of the person to greet.
pub name: String,
}
pub struct Greet;
impl DynAomiTool for Greet {
type App = HelloApp;
type Args = GreetArgs;
const NAME: &'static str = "greet";
const DESCRIPTION: &'static str =
"Use when the user wants a friendly greeting. Takes a name and returns a hello message.";
fn run(_app: &HelloApp, args: GreetArgs, _ctx: DynToolCallCtx) -> Result<Value, String> {
Ok(json!({ "message": format!("Hello, {}! Welcome to Aomi.", args.name) }))
}
}
const PREAMBLE: &str =
"When the user asks to be greeted, call the greet tool with their name.";
dyn_aomi_app!(
app = HelloApp,
name = "hello-aomi",
version = "0.1.0",
preamble = PREAMBLE,
tools = [Greet,],
namespaces = []
);Build, and try it locally
aomi-run loads the compiled plugin and opens a REPL against a real model, so you can see which tools it picks before you ship. It needs a provider key, ANTHROPIC_API_KEY by default, or --provider openai or openrouter. Host namespaces are stubbed in the dev runtime; the real backend is not present.
cargo build --release
aomi-run target/release/libhello_aomi.dylib # .so on Linux, .dll on Windows
aomi-run target/release/libhello_aomi.dylib --provider openai --model gpt-5 --env-file .env.localCommit and push
Deploy works from a pushed commit. Local changes you did not push do not exist as far as the deploy is concerned.
printf '/target\n/.aomi\n' > .gitignore
git init && git add aomi.toml Cargo.toml Cargo.lock src .gitignore && git commit -m "init hello-aomi"
git pushConnect the repo, once
Installs the Aomi Build GitHub App on your repo and saves your activation token. GitHub sends you to a callback page that can look like a 404; the number at the end of its URL, /installations/<number>, is the installation id the CLI asks for.
aomi-build connect --platform community --repo you/hello-aomiDeploy
One command runs the whole lifecycle: sdk check, preflight, deploy run, wait for ready, activate, then verify loaded. It opens a PR on the platform repo, waits for the platform build, activates, and verifies the runtime loaded it. You are done when you see active=true artifact_ready=true loaded=true. Add --dry-run first to see the plan without deploying.
export AOMI_BACKEND_URL=https://api.aomi.dev
export AOMI_APP_ACTIVATION_TOKEN=<your-token>
aomi-build deploy --repo you/hello-aomi --target-tag prod
aomi-build deploy status # add --json for machinesShip an update
Open chat.aomi.dev, find your App, and talk to it.
cargo test
git add -A && git commit -m "Update" && git push
aomi-build deploy --repo you/hello-aomi --target-tag prodThree things that bite
- Tokens. An app token is scoped to one App. Activation onto prod is a platform-level action and needs a platform token. If you see app token is not authorized for platform-level actions, that is why. Ask the Aomi team in Discord.
- The SDK bump. When the platform raises the required aomi-sdk version, every release built against the old one stops loading and your App disappears from the picker with no error. The tell in aomi-build deploy status is artifact_ready=false and not loaded. Fix: aomi-build sdk fix, rebuild, commit, redeploy.
- Secrets. If your plugin calls an outside API, declare the key in code with Secret::new("NAME", "description", required) and list it in the macro. Users supply the value through the Build platform's Environment tab or aomi secret add. Never put a literal token in aomi.toml.
Design a focused tool surface: three to eight tools is a useful target. Keep read-only tools separate from tools that stage or submit actions.
Build platform
The Build platform
build.aomi.dev is the hosted control plane for Aomi Apps. Everything aomi-build does has a web interface, and both drive the same backend, so a project connected from the terminal shows up in the browser and the other way round.
Sign in with GitHub
Use the account that owns the repositories you want to connect. The whole console is scoped to that identity.
Build from an idea, or from a template
Build takes a plain English description (shortcuts: Arb bot, OpenAPI agent, Plan from idea; templates: Arbitrage Bot, OpenAPI Agent, Trading Agent), generates the plan and the files, compiles, smoke tests, then ships to Projects. Review the generated work and its test results before deploying. Or New app: install the Aomi Build GitHub App on your personal account, then Start from the template (forks aomi-labs/playground-example) or Import from GitHub.
Deploy and activate
The wizard deploys the commit, waits for the platform build, and activates the release. If the App declares required secrets, activation is blocked until you set them. The last step opens your live App in chat.aomi.dev.
Operate
Every project has five tabs: Home (status, environment, usage, monetization), Deployments (promote or deactivate per row), Providers, Environment, Chat. Redeploy from Linked Repository runs deploy, CI and activate against the repo's current head.
Keys, the right way
Account, Providers stores your OpenAI, Anthropic and OpenRouter keys; they fund inference and can be assigned per project. Your App's own API credentials go in the project's Environment tab. Both are write-only: after you paste a value, only its prefix is ever shown again.
SDK upgrades from the browser
When the platform bumps the required aomi-sdk, Build shows the version and offers a one-click upgrade: it opens a pull request on your repository (branch aomi/sdk-<version>) that rewrites the pin, waits for you to merge, then redeploys. The CLI equivalent is aomi-build sdk fix.
Organization-owned repositories are not yet supported on the web platform. Fork into your personal account, deploy from there, then transfer the repository back. The deployment stays live.
Widget
The widget, an App inside your React app
AomiWidget adds Aomi chat, threads, wallet connection and transaction approval to a React 18 or 19 application. Your app chooses the App (by numeric Application ID) and the wallet provider: a browser wallet, Para or Privy. Aomi resolves the App's tools and execution settings from the ID. The widget runs on your origin with an origin-bound session; there is no allowlist to register. Hosted integrations must use HTTPS; HTTP works only on localhost.
Install
npm install @aomi-labs/widget-libPublic configuration
Safe to expose to the browser. Never put an App key, provider secret, paymaster or gas policy credential, treasury configuration, or private key in frontend code.
# Next.js (.env.local); Vite uses VITE_ instead of NEXT_PUBLIC_
NEXT_PUBLIC_AOMI_API_URL=https://chat.aomi.dev
NEXT_PUBLIC_AOMI_APPLICATION_ID=123
# only if you use that provider
NEXT_PUBLIC_PARA_API_KEY=your_public_para_api_key
NEXT_PUBLIC_PRIVY_APP_ID=your_public_privy_app_idMount it
Browser wallet mode authenticates an existing EVM or Solana wallet. For Para or Privy, also import @aomi-labs/widget-lib/providers/para or /providers/privy and pass auth={{ kind: "embedded_wallet", provider: "para", environment: "PROD" }}.
"use client";
import { AomiWidget } from "@aomi-labs/widget-lib";
import "@aomi-labs/widget-lib/styles.css";
export default function AssistantPage() {
return (
<AomiWidget
applicationId={process.env.NEXT_PUBLIC_AOMI_APPLICATION_ID!}
apiUrl={process.env.NEXT_PUBLIC_AOMI_API_URL!}
auth={{ kind: "browser_wallet" }}
height="calc(100dvh - 32px)"
/>
);
}Who owns what: your application owns the Application ID, the provider choice and the presentation. The widget owns sign-in, wallet connection, threads, chat, transaction review and signing requests. The user's wallet owns the signature. Switching providers changes how users sign in; it does not change which App handles the conversation.
Client SDK and REST API
Client SDK and REST API
Two versioned HTTP resources cover the whole surface. /v1/agent owns conversation state: stateful turns, progress events, actions and sessions. /v1/pipeline is stateless: catalog discovery and the build, simulate, commit lifecycle. The TypeScript client wraps both.
TypeScript
npm install @aomi-labs/client
export AOMI_BASE_URL="https://chat.aomi.dev"
// example.ts, run with: npx tsx example.ts
import { Aomi, type MessageEvent } from "@aomi-labs/client";
const aomi = new Aomi({ baseUrl: process.env.AOMI_BASE_URL! });
const sessionId = crypto.randomUUID();
await aomi.agent.run("Remember that my demo color is cobalt.", { sessionId });
const result = await aomi.agent.run("Reply with only my demo color.", { sessionId });
console.log([...result.messages].reverse().find(m => m.sender === "agent")?.content);Reusing sessionId continues the same conversation. No API key is needed to start: the SDK opens in guest mode and creates an anonymous session on the first request. Guest mode is for evaluation; use the OAuth device flow for account-owned sessions and protected actions. The Aomi facade gives you aomi.agent, aomi.pipeline, aomi.auth and aomi.raw (the wire-close AomiClient).
The unified Aomi class is documented from origin/main. The latest published @aomi-labs/client on npm may not export it yet; verify the exported types before pinning, or use the prerelease provisioned for your environment.
Raw HTTP
-H "Authorization: Bearer $AOMI_ACCESS_TOKEN"
-H "Idempotency-Key: <unique-per-mutation>" # required on every mutationTokens are bound to an exact resource: an Agent token cannot call Pipeline, and REST tokens cannot call MCP. Send and receive JSON. Capture X-Request-Id from failed responses and respect Retry-After. The contract is served at /openapi.json, but pin types from the released TypeScript client rather than fetching it at startup. Interactive playgrounds for every endpoint: aomi.dev/docs/api-reference.
Telegram bots
Telegram bots on Aomi
A deployed App can become a Telegram bot without you running a server. Aomi hosts the bot. One bot can front one App or your whole catalog. Telegram is live today; Discord, Slack and iOS are coming. You need an App that is active and loaded (aomi-build deploy status confirms it) and a Telegram account. That is all.
Create the bot in Telegram
Open @BotFather, send /newbot, give it a name and a username ending in bot. Copy the token it returns (it looks like 123456789:AAE...) and keep it private. If it ever leaks, /revoke and get a new one.
Register it on Aomi
Go to build.aomi.dev/integrations, sign in with the GitHub account your Apps are deployed under, and in the Telegram section register a bot: an optional label, the token, the Apps it should serve, the primary App it opens with, and a thread mode (single, one running conversation per user, is simplest). Aomi verifies the token, stores it encrypted, and turns on the webhook. Nothing to deploy. Your App must be active to appear in the list.
Talk to it
Open t.me/<your_bot_username>, send /start, and type. The bot is your App: it answers questions, reads live data, and walks a user through a transaction with simulate before sign. Add it to a group and people talk to it by mentioning it.
Commands your users get for free
Bots you can look at. World Markets is an in-development Telegram asset manager for World Markets on MegaETH: it reads account and market state from the exchange contract, checks an investment mandate, and previews a trade without presenting it as executed, failing closed when it cannot prove the resulting portfolio state.
Security
Permissions and guards
Aomi treats a model's output as a proposal, never as authority. Composition is open. Signing is gated. A prompt, an App or a skill can request an action. None of them can grant themselves permission to sign, and the wallet's policy stays authoritative across chat, scheduled work and embedded surfaces.
Three independent controls
- Signing policy. What kind of approval one linked wallet requires: approve each request, permit an authorized automatic path, or block signing. Modes are denied, manual, client_auto, auto, changed only through a wallet-signed permit. A policy belongs to one wallet; linking another does not copy it.
- Signing capability. A policy that permits an automatic path still needs the wallet session or provider authorization to exist for that exact wallet. If not, Aomi stops rather than substituting another signer. Delegated auto signing exists only for embedded wallets (Privy, Para) under a revocable grant; self-custody wallets sign every request on the user's own device.
- Transaction constraints. Permission to sign does not make every transaction acceptable. Simulation, guards on chains, contracts, function selectors and approval spenders, per-call USD caps, and protocol checks on beneficiary and spender fields all run first.
Simulation passing is evidence about one payload against one view of chain state. It does not prove state will hold, that a contract is economically safe, or that the action is authorized. That is why the other controls exist. Read the permission model and transaction safety before you build an execution workflow.
Examples
Projects on Aomi
Each project keeps its own rules and uses Aomi for the loop, the simulation, or the signature. Use them as references, then build your own.
Somm Finance
Actively managed DeFi strategies. Agentic Somm wraps Somm's five existing endpoints as typed tools, gives the agent its investment mandate in the system prompt, and renders the recommendation as a product-native card. Somm keeps its strategy, data and risk model. The same App serves the product frontend and Telegram. Aomi does not host a Discord bot.
Kuroko
An AI hybrid trading platform for prediction markets. Live Polymarket context in every message, market scoring, paper, testnet and live flows, stop-loss and take-profit guards. Uses the widget as its interface and @aomi-labs/client for trade intents. Unverified markets stay in simulation mode.
aomi-trader
A Hyperliquid trader that watches BTC-PERP, reads position and equity, and produces a LONG, SHORT, CLOSE or PASS decision each cycle. One session with @aomi-labs/client; the product owns risk threshold, size and cooldown. Proof that an Aomi product does not have to look like chat.
World Markets
In development. A Telegram asset manager on MegaETH that separates a product-specific mandate from the general pipeline: the App owns World Markets context and policy checks, Aomi supplies the loop, the channel, simulation and signing.
Teams in production: Somm Finance · Para · Khalani · Swig · Molinar.
Aomi runs a simulate-first, non-custodial execution path on Arc mainnet (5042) and testnet (5042002), with a Commit Service that confirms settlement rather than trusting a transaction hash.
If you get stuck
Reach out in Discord. Include your project, the chain you are on, the action you want to execute, and a repo or minimal reproduction if you are reporting a problem. Never include secrets.