> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rekt.money/llms.txt
> Use this file to discover all available pages before exploring further.

# Building an agent

> The operating brief for an LLM driving Knockout: the loop, the refusals, the units, orders and closes, and the five things an autonomous client must never do.

This page assumes the reader is a capable model with no prior context, building a client that
decides and sends without a human watching each action. It is short, dense and imperative. Every
section links to the page that explains it properly — read this first, then follow the links you
need.

> [!WARNING]
>
> Knockout is a **barrier product**. A position can be knocked out by a small move and
> end at zero. An autonomous client is a client that can lose money quickly and without anyone
> noticing. Build the read path and the refusal path before you build the send path.

## The loop

Five steps, in this order. Skipping step 2 or 3 is how a client ends up learning the protocol from
reverted transactions.

**1. Read the protocol**

Config, vault and market, decoded from the chain — [Read the protocol](https://docs.rekt.money/sdk/reading.md). Addresses are
derived locally with `configPda`, `vaultPda`, `marketPda`, so you never trust an address printed
on a page. **Never cache `config.params`**: every field in it is governed and can move without a
program upgrade.

**2. Price it**

`openPreview` / `costToOpen` tell you what the trader is actually charged and the gross payout at
the target, which is before the exit fee and the share of the gain the terms withhold. A losing close
above the barrier pays what is left after the loss, less a loss tax on that loss and then the exit
fee: see [what a close pays](https://docs.rekt.money/sdk/positions.md#what-every-close-would-pay-right-now). Do not
recompute protocol arithmetic yourself — a second derivation of a number is how a client and a
chain come to disagree.

**3. Ask what would refuse it**

`openGates` and `settleGates` return every gate with the measured value and the threshold —
[Reading gates](https://docs.rekt.money/sdk/gates.md). Branch on the first failing gate.

**Order is a per-function property.** `openGates` follows the program's order for an open.
`settleGates` emits its own sequence and does not reproduce the program's settle order row for
row: it places the reason row by the cause it reports, ahead of the price row or behind the
exponent row.
Neither report reads the guardian flags; read `config.oracleFrozen` and
`config.settlesDisabled` yourself. An agent that sends to find out is paying for information it
could have had for free.

**4. Send, then wait for the step to end**

**An open, an add and a close request carry no quote.** Build an open with
`ix.open(accounts, args, priceAccountsFor(market, config, 'open'))`, an add with
`addCollateralFor` and a close request with `requestCloseFor`, sign, send, and then wait for
the event that ends each step: `EntryFilled` or `OpenVoided` for an order, `CollateralAdded` or
`AddReversed` for an add, `SettlementPriced` for a close. A landed transaction is an order or a
request, never the result. [Orders and closes](https://docs.rekt.money/sdk/orders.md) is the contract, and
[Opening](https://docs.rekt.money/sdk/opening.md) has the code.

A quote matters only if you send an instruction that carries one yourself: a `settle`, a
`stamp_book` or a `set_take_profit`. Those age out in **slots, not seconds**, judged when the
program runs rather than when you obtained the quote. **Obtain a new quote immediately before
signing**, sign locally, and never put a human approval between the two. See
[Settling](https://docs.rekt.money/sdk/settling.md) and [Quotes and freshness](https://docs.rekt.money/sdk/quotes.md), and
[Getting prices](https://docs.rekt.money/sdk/prices.md) to obtain one.

**5. Reconcile**

Compare what you predicted against what the chain moved. A client that never checks is a client
that will be wrong quietly. Decode the events rather than inferring from balances: the SDK
exports `decodeSettlementPriced`, `decodePositionOpened`, `decodePositionStamped`,
`decodeEntryFilled`, `decodeOpenVoided`, `decodeAddReversed` and `decodeSettlementReceipt`, and
`readTradeHistory` reads them back off a cluster. Join every event on `openerTag`.

## Refusals: branch on `retryable`, never on the name

The error catalogue is generated from the SDK's client IDL, so it cannot drift from what the chain
raises — [Error handling](https://docs.rekt.money/sdk/errors.md). The one field that matters to an autonomous client is
`retryable`:

| `retryable` | Do |
| - | - |
| `never` | Fix the request. Retrying is an infinite loop. |
| `after-state-changes` | Re-evaluate when the world moves on its own — a settle, a new slot. Back off. |
| `after-governance` | Stop retrying on a timer. Only an instruction signed by the venue's config authority clears it; poll the flag the `fix` names and alert an operator. |
| `immediately` | Retry on the next slot. These are almost all price freshness. |

Resolve with `errorForCode` / `errorForName`. **Do not pattern-match error strings.** The names are
an ABI and the codes are stable; your regex is neither. For the order and close codes, 6203 to 6238,
bind to `retryClassOf(code)`: it says "done", "send the other instruction" and "retry with the right
quote", which `retryable` cannot.

Two refusals that mean something different from what they sound like:

* **`PositionSlotsFull`** — the *trader's book* is full, not the venue. A book holds a fixed number
  of positions, chosen when it was created and changeable afterwards.
* **`SideStakeCapReached`** — raised only on a market that has a side limit set. No market has one
  set. If one is set and the side is full, back off; do not spin. A pool that cannot cover an order is
  not a refusal: the order is returned with the whole stake.

## What constrains you, whatever you are trying to do

These hold on chain and no client can talk its way past them:

* **The cover rule.** A fill is admitted only if the pool can cover it. The number of concurrent
  positions the venue admits depends on the pool and the queue. An order that does not fit is returned
  with the whole stake and no fee: treat it as a state, not a fault.
* **A win may be paid later.** A win is paid in full, but part of it may be paid later, in order, and
  `SettlementPriced.trader` is only what was paid now. Never present it as the amount won: read
  `SettlementQueued`.
* **Money in = money out on every path.** The program never mints and never burns.
* **The pauses close the entry, not the exit.** A pause of the venue or of one market stops opens,
  adds and take-profit retargets; `settle` continues. An order already placed is still
  filled or returned.
* **An order is not a position, and a request is not a close.** The entry is the venue's next price
  after a short delay, and the exit is the first price after the close's target, by the window rule.
  Never show a price from the tap as the entry or the exit.
* **A stop can freeze both prices and closes.** An oracle freeze refuses opens, adds, close requests,
  expiry marks, `stamp_book`, `lastResort` and the return of an order or add that needs a price, and
  starves `settle` and `set_take_profit` of a price. A settle stop refuses all of those, every
  `settle` reason, `set_take_profit` and the return of an unfilled order or add. Only the config
  authority lifts either. Read `config.oracleFrozen` and `config.settlesDisabled`, and treat either as
  a stop, not a retry.
* **A market with trading hours only accepts opens and adds during its own session.** The calendar is on
  the market account (`market.sessions`).
  Read it, or call `availability()` for the state and the next open, and do not assume that a market
  is always open. See [markets](https://docs.rekt.money/markets.md).

## Units

* USDC in **base units**, 6 decimals. `250000` is \$0.25.
* A payout can be large relative to collateral. Format money as dollars in anything a human reads; a
  figure printed as `25007500` will be misread as twenty-five million.
* Rates and limits are in basis points or micro-basis-points on chain. Read them from the account,
  never from a constant you copied.

## Who signs

An open, an add and a close request carry no quote, so a person can approve each one in a wallet,
and an autonomous client signs locally. The instructions that carry a quote are `set_take_profit`
and any `settle`, `stamp_book` or `prove_price` you send yourself. A quote ages out in slots, so a
human approval between the quote and the send cannot land: sign those locally.

If you are trading a book that is not your own, one option is for the owner to authorise a
**session-key delegate** your agent signs with; if you are trading your own, you are already a local
signer. How you sign is your decision. Put any human approval on the **authorisation**, which
carries no price and races nothing.

If you choose the program's session-key delegate, it is five moves — [session keys](https://docs.rekt.money/sdk/sessions.md)
has working code for each:

1. **Generate.** An ordinary keypair, made where the trades are signed. It is not the owner's wallet
   and is never derived from it.
2. **Authorise.** `authorizeSession` — one instruction the owner signs, setting the expiry, the
   spend window and the SPL token allowance together.
3. **Fund it.** The fee payer must sign, so on this route it is not the human — the session key
   itself, or a separate sponsoring fee payer you add. Give whichever pays its own lamports and
   watch the balance.
4. **Sign every trade with it.** `authority` is the session key, `delegate` is
   `delegatePda(owner).address`, and the book, the token account and the money all stay the
   owner's.
5. **Revoke when the mandate ends.** `endSession` closes the account and drops the SPL allowance in
   one instruction, in the same slot, and returns the rent.

Gate before you send: `delegateGates` covers the four refusals `openGates` does not model, and
`sessionAllowanceGates` covers the SPL allowance — a **total that draws down and never refills**,
which is what actually ends most long sessions, arriving from the token program as
`InsufficientFunds` in none of this program's error shapes.

> [!NOTE]
>
> **A session key can open AND request a close**, unless its grant carries the no-close
> restriction. The program authorises a `request_close` for the owner or for an unexpired session key
> bound to them, and the request saves a wallet prompt and races nothing. The settle that completes
> it is sent by anyone, and the other six close reasons are permissionless and need no signature
> from either.

## Five things an autonomous client must never do

1. **Never route around a refusal.** A guard that refuses you knows something you do not. Read the
   gate, fix the request.
2. **Never cache governed state.** `config.params`, market parameters and the session calendar all
   move on chain. Re-read them, and show how old your copy is.
3. **Never put a credentialled RPC endpoint in a command line, a log, a commit or a screenshot.**
   Reference it by variable name — [Installation](https://docs.rekt.money/sdk/installation.md).
4. **Never present a model output as a fact.** An estimate from your own model is yours to compute
   and yours to label. What the chain settled is a fact; what your model expects is not.
5. **Never sign a second order for the same intent after a timeout.** Inside one blockhash life, send
   the same signed bytes again. A second signature is a second order, and both can land.

## Where to go next

| You want | Read |
| - | - |
| a bot that quotes, opens and closes | [Quickstart](https://docs.rekt.money/sdk/quickstart.md) |
| a working read path in one file | [Read the protocol](https://docs.rekt.money/sdk/reading.md) |
| the docs as an MCP server, and a skill file | [Build with an AI agent](https://docs.rekt.money/sdk/ai.md) |
| **orders, fills, closes and what never to assume** | **[Orders and closes](https://docs.rekt.money/sdk/orders.md)** |
| **to sign with a session key** | **[Session keys](https://docs.rekt.money/sdk/sessions.md)** |
| to understand `6007` and what to do about it | [Quotes and freshness](https://docs.rekt.money/sdk/quotes.md) |
| every refusal, before you send | [Reading gates](https://docs.rekt.money/sdk/gates.md) |
| to open a position | [Opening](https://docs.rekt.money/sdk/opening.md) |
| to read and value a book | [Positions](https://docs.rekt.money/sdk/positions.md) |
| to close a position | [Settling](https://docs.rekt.money/sdk/settling.md) |
| to decode accounts, events and errors | [Reference](https://docs.rekt.money/sdk/reference.md), [Error handling](https://docs.rekt.money/sdk/errors.md) |
| what the product actually is | [How it works](https://docs.rekt.money/how-it-works.md), [Risk](https://docs.rekt.money/risk.md) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.