OlaiDocs
Open the desk

Concepts

How it works

One question, from asking to a filled order, with every step named.

One question, end to end, on a live order. This is the main sequence from ARCHITECTURE.md.

diagram

The same story in words

The question arrives. POST /api/ask with the owner's bearer token. SessionRunner.ask (packages/agent/src/session/session.ts) mints a session id of the form ol-<uuid>, writes a question line to the ledger, and starts the analyst.

The agent shops for data. The brain (packages/agent/src/brain/analyst.ts) has one search tool, search_bazaar. It searches Binance's public B402 Bazaar, which needs no key and no account. Olai keeps only listings the Binance wallet can actually pay for and only the eight cheapest, and it clamps whatever price cap the model asked for down to the rulebook's maxDataSpendUsdPerCall. The model cannot raise its own budget.

The agent buys one call. The buy_data tool checks the rulebook first, in code, as a payment action. If the rulebook refuses, the wallet is never asked to sign. If it allows, the buyer (packages/agent/src/x402/buyer.ts) calls the merchant, reads the 402 response, asks baw x402-payment preview for signable options, picks one, signs once, and replays the request with the signed header. The merchant answers with the data and a settlement header carrying the on-chain transaction hash. That hash goes in the ledger next to the cost.

The agent reads the market for free. Four read tools go through Binance's exchange REST API on the sub-account: read_ticker, read_order_book, read_klines and read_account. These cost nothing and touch no money. This same reasoning was meant to go through the Binance MCP server; Binance's consent screen turned Olai's own client away, so these reads and the order below both go over signed REST calls instead. See Why Binance Agent OS.

The agent proposes. The only output that leaves the brain is a propose call that parses against proposalSchema: a summary, the reasoning, one action (order or hold), a confidence between 0 and 1, the data it used with costs and transaction hashes, and the risks it sees. A proposal is a request for approval, never an instruction to the exchange.

The rulebook checks it. evaluate in packages/agent/src/policy/engine.ts runs against a fresh account snapshot. A refused proposal writes a rule.refused line and the owner never sees a pending order. An allowed one writes a proposal line and waits.

The owner decides. POST /api/sessions/:id/approve or /reject. Approval is a real HTTP call with the owner's token. It is never inferred from anything the model wrote. On the desk that call is the Approve button on the proposal card, and Reject carries a one-line reason with it.

The order goes out, once. On approval the rulebook runs a second time, against a snapshot taken at that moment, because the day's loss, the open positions and the kill switch can all have moved while the proposal sat waiting. Then SessionRunner marks the session as ordered before calling the exchange, so a send that throws cannot be retried into two orders. The ledger gets approval, then order.sent, then order.filled or order.failed.

What each piece is

Piece Where Job
Owner API src/api/app.ts The only door in. One user, one token.
Session runner src/session/session.ts The only thing that can place an order.
Brain src/brain/analyst.ts The Claude tool loop. Advises, never executes.
Rulebook engine src/policy/engine.ts A pure function. Runs before every payment and every order.
Ledger src/ledger/ledger.ts Append-only SQLite, hash chained.
Bazaar client src/bazaar/client.ts Public discovery of paid endpoints.
x402 buyer src/x402/buyer.ts One paid HTTP call, start to finish.
Wallet wrapper src/x402/baw.ts The baw CLI. Olai holds no keys.
Exchange REST client src/exchange/rest.ts HMAC-signed calls to the Spot REST API. The live trading door.
MCP client src/mcp/ OAuth, the session, and the tool-name map. Coded and tested, held unused.

All paths are relative to packages/agent.