---
name: lume
description: >
  Trade on Lume prediction markets. Browse events and markets,
  place buy/sell orders, manage positions, check balances, view
  price charts, and participate in discussions. Handles agent
  onboarding (gasless Safe wallet deployment, contract approvals,
  relay fee payment), account funding with USDC on Monad, and
  full order lifecycle management. Use when the user wants to
  trade predictions, check market prices, manage a prediction
  market portfolio, set up a new trading agent, fund a wallet,
  or interact with the Lume platform.
license: MIT
metadata:
  author: EternisAI
  version: '0.1.0'
hooks:
  PreToolUse:
    - matcher: 'Bash'
      hooks:
        - type: command
          command: '${CLAUDE_SKILL_DIR}/scripts/check-and-install.sh'
          once: true
          statusMessage: 'Checking Lume SDK...'
---

# Lume Trading Skill

## Command Routing

This skill supports subcommands via args. Route based on the first word:

| Args                       | Action                                                        |
| -------------------------- | ------------------------------------------------------------- |
| `login`                    | Run the **Login Flow** below                                  |
| `logout`                   | Delete the credentials file and confirm                       |
| _(anything else or empty)_ | Run the **Proactive Greeting** below, then handle the request |

### Proactive Greeting (default `/lume` with no args or open-ended args)

When the user runs `/lume` with no subcommand, do NOT show a static menu of options.
Instead, deliver a short, contextual, actionable greeting.

**CRITICAL: Do NOT narrate your internal steps.** Never say things like "let me check
your login state", "following the proactive greeting flow", "fetching market data",
etc. Just silently execute the steps and present the final greeting directly.
The user should only see the polished greeting, not how you built it.

Follow these steps:

1. **Check login state.** Silently read `${CLAUDE_SKILL_DIR}/.lume-credentials`.

2. **Fetch trending markets and (if logged in) balance** using the SDK.
   - For public reads (not logged in), create a `LumeClient()` with no
     arguments — no private key is needed for public queries.
   - If the user is logged in, create a `LumeClient(private_key=pk)` using
     their key from `.lume-credentials`.
   - Call `client.get_all_events(first=5, status="ACTIVE")` — get active events.
   - For each event, call `client.get_event(event_id=e.id)` to get full market
     and outcome details (including `bestBid`/`bestAsk` pricing).
     Note: `get_all_events()` returns lightweight `Outcome` objects with only
     `id`, `label`, and `token_id` — no pricing data. You must use `get_event()`
     to get `bestBid` and `bestAsk` on outcomes.
   - From the detailed results, find the first event that has an outcome with
     a `bestBid`. Use `from_atomic()` to convert the price for display.
   - If logged in, also call `client.get_onchain_balance()` to get the available
     on-chain USDC balance in the proxy wallet. Use the `available_decimal` field
     for display. Note: `get_balance()` returns the platform ledger balance which
     may not reflect on-chain funds — always prefer `get_onchain_balance()` for
     actual wallet balance.

3. **Compose the greeting** from the data. Output ONLY the greeting — nothing else.

   **If NOT logged in + have trending market:**

   > "Will ETH hit \$5K by July?" is trending at \$0.43 Yes. Run `/lume login` to start trading, or ask me about any market.

   **If NOT logged in + no trending data:**

   > {N} active events on Lume right now. Run `/lume login` to start trading, or ask me about any market.

   **If logged in + balance + trending market:**

   > Lume connected — \$42.50 available. "Will ETH hit \$5K by July?" is trending at \$0.43 Yes. What would you like to trade?

   **If logged in + not fully onboarded (check `get_onboarding_status()`):**

   If Safe is not deployed, run the onboarding steps (7-8 from Login Flow) silently,
   then show the appropriate greeting. If the relay fee is unpaid and the wallet
   has USDC, pay it automatically.

   **If logged in + zero balance:**

   > Lume connected but your wallet is empty. "Will ETH hit \$5K by July?" is at \$0.43 Yes. Fund your wallet to trade, or ask me about any market.

   **If logged in + balance + no trending data:**

   > Lume connected — \$42.50 available. {N} active events to explore. What catches your eye?

4. **If the user provided additional text** beyond `/lume` (e.g., `/lume what's hot`),
   skip the greeting and directly handle their request using the relevant sections below.

**Rules for the greeting:**

- Output ONLY the greeting text. No preamble, no "let me check...", no status updates.
- Keep it to 1-2 sentences max. No bullet lists, no menus, no "here's what I can do".
- Always include one concrete data point (a market price, number of events, or balance).
- End with an open prompt, not a list of options.
- If fetching live data fails, fall back to: "Lume connected. What would you like to explore?"

### Login Flow (`/lume login`)

When the user runs `/lume login`, follow these steps exactly:

1. **Check if already logged in.** Read the credentials file at
   `${CLAUDE_SKILL_DIR}/.lume-credentials`. If it exists and contains a
   `PRIVATE_KEY=` line, inform the user they are already logged in and show
   the EOA address (derive it from the key using the SDK). Ask if they want
   to re-login (overwrite).

2. **Ask the user** using `AskUserQuestion`:

   > Do you have an existing private key, or would you like to generate a new wallet?
   >
   > 1. **Import existing** — I have a private key
   > 2. **Generate new** — Create a fresh wallet for me

3. **If importing:** Ask the user to paste their private key directly in
   the chat. Simply tell them:

   > Paste your private key (0x...) and I'll save it locally.

   Then validate and save. The key is only stored in the local
   `.lume-credentials` file.

4. **If generating:** Run the SDK to create a new wallet:

   ```bash
   PYTHON=/tmp/lume-env/bin/python
   $PYTHON -c "
   from lume import generate_wallet
   pk, addr = generate_wallet()
   print(f'PRIVATE_KEY={pk}')
   print(f'ADDRESS={addr}')
   "
   ```

   Show the user their new address and **warn them to back up the private key**
   since it's only stored locally.

5. **Save credentials.** Write the file `${CLAUDE_SKILL_DIR}/.lume-credentials`:

   ```
   PRIVATE_KEY=0x...
   ```

   This file is gitignored via the `.lume-credentials` pattern.

6. **Verify.** Use the SDK to create an `AgentClient`, call `register()`, and
   display the EOA address and proxy wallet. Confirm login was successful.

7. **Complete onboarding (gasless).** Immediately after registration, deploy the
   Safe wallet and set up contract approvals. This is gasless and must happen
   before the user can trade. Use the helper functions from the SDK examples:

   ```bash
   PYTHON=/tmp/lume-env/bin/python
   PRIVATE_KEY=<the saved key>
   # Download helper if not cached
   if [ ! -f /tmp/safe_wallet_operations.py ]; then
     gh api repos/EternisAI/lume-sdk/contents/examples/safe_wallet_operations.py \
       --jq '.content' | base64 -d > /tmp/safe_wallet_operations.py
   fi
   $PYTHON -c "
   import sys
   sys.path.insert(0, '/tmp')
   from safe_wallet_operations import build_safe_deploy_calldata, build_approvals_calldata
   from web3 import Web3
   from lume import AgentClient, SafeWalletManager
   from lume.constants import get_config_with_env_overrides

   pk = '$PRIVATE_KEY'
   config = get_config_with_env_overrides()
   rpc_url = config.rpc_url

   agent = AgentClient(private_key=pk)
   agent.register()

   w3 = Web3(Web3.HTTPProvider(rpc_url))
   wallet_mgr = SafeWalletManager(private_key=pk, rpc_url=rpc_url)

   safe_target, safe_data = build_safe_deploy_calldata(wallet_mgr)
   safe_address = wallet_mgr.compute_safe_address()
   approvals_target, approvals_data = build_approvals_calldata(w3, safe_address, pk, rpc_url)

   result = agent.register_wallet_user(
       safe_deploy_target=safe_target,
       safe_deploy_data=safe_data,
       approvals_target=approvals_target,
       approvals_data=approvals_data,
   )
   print(f'SUCCESS={result.success}')
   print(f'PROXY={agent.proxy_wallet}')
   if result.error:
       print(f'ERROR={result.error}')
   "
   ```

   After successful deployment, tell the user:

   > Wallet set up! Send USDC on Monad to your proxy wallet:
   > `<proxy_wallet_address>`
   > Minimum 1 USDC (relay fee) + whatever you want to trade with.
   > The relay fee will be paid automatically when you first interact after funding.

### Logout Flow (`/lume logout`)

Delete `${CLAUDE_SKILL_DIR}/.lume-credentials` and confirm to the user.

### Authentication for All Other Commands

Before running any SDK operation that requires a private key:

1. Check if `${CLAUDE_SKILL_DIR}/.lume-credentials` exists.
2. If not, tell the user: _"You need to log in first. Run `/lume login` to set up your wallet."_
   and stop.
3. If it exists, load the `PRIVATE_KEY` value and pass it to the SDK client:
   ```bash
   PRIVATE_KEY=$(grep '^PRIVATE_KEY=' "${CLAUDE_SKILL_DIR}/.lume-credentials" | cut -d'=' -f2)
   ```
4. **Check onboarding status** via `agent.get_onboarding_status()`. If not fully
   onboarded, silently complete the remaining steps before proceeding:
   - **Safe not deployed:** Run the Safe deployment + approvals from Login step 7.
   - **Relay fee not paid:** Check on-chain balance via `agent.get_onchain_balance()`.
     If >= 1 USDC, automatically pay the relay fee:

     ```bash
     # Download helper if not cached
     if [ ! -f /tmp/safe_wallet_operations.py ]; then
       gh api repos/EternisAI/lume-sdk/contents/examples/safe_wallet_operations.py \
         --jq '.content' | base64 -d > /tmp/safe_wallet_operations.py
     fi
     $PYTHON -c "
     import sys
     sys.path.insert(0, '/tmp')
     from safe_wallet_operations import build_relay_fee_calldata
     from web3 import Web3
     from lume import AgentClient
     from lume.constants import get_config_with_env_overrides

     pk = '$PRIVATE_KEY'
     config = get_config_with_env_overrides()
     rpc_url = config.rpc_url

     agent = AgentClient(private_key=pk)
     agent.register()

     w3 = Web3(Web3.HTTPProvider(rpc_url))
     fee_target, fee_data = build_relay_fee_calldata(w3, agent.proxy_wallet, pk, rpc_url)
     result = agent.pay_relay_fee(target=fee_target, data=fee_data)
     print(f'SUCCESS={result.success}')
     if result.error:
         print(f'ERROR={result.error}')
     "
     ```

     If insufficient funds, tell the user:
     _"Your wallet needs at least 1 USDC for the one-time relay fee. Send USDC to `<proxy_wallet>` and try again."_

## Python Requirement

The Lume SDK requires Python >= 3.12. The setup hook (`scripts/check-and-install.sh`)
automatically creates a venv at `/tmp/lume-env` and installs the SDK on first use.

When running Python code, always use the venv interpreter:

```bash
PYTHON=/tmp/lume-env/bin/python
$PYTHON -c "your code here"
```

Never use bare `python3` — it may point to an older system Python without the SDK.

## Overview

Lume is a prediction market platform on the Monad blockchain. Users trade binary
and categorical outcome shares (e.g., YES/NO) whose prices reflect the
crowd-estimated probability of real-world events. Orders are matched off-chain
for speed; settlement and position custody happen on-chain via Gnosis Safe
wallets and the Conditional Token Framework (CTF).

This skill gives an AI agent everything it needs to:

- Set up and onboard a new trading agent (gasless)
- Fund the agent's wallet with USDC
- Browse live events and markets
- Read order books and price history
- Place, cancel, and monitor limit orders
- Track positions and collateral balance
- Post and vote on discussion comments
- Create user bets (new events)
- Subscribe to real-time order and position updates

The Python SDK package is called `lume`.

### Agent workflow at a glance

1. **Setup** -- Install SDK, create `AgentClient`
2. **Register** -- `agent.register()` to authenticate and get proxy wallet
3. **Onboard** -- `register_wallet_user()` to deploy Safe + approvals (gasless)
4. **Fund** -- User sends USDC on Monad to `agent.proxy_wallet`
5. **Relay fee** -- `pay_relay_fee()` to enable gasless transactions (1 USDC)
6. **Trade** -- `create_and_place_order()`, `cancel_order()`, etc.

## Setup

### Install

```bash
pip install git+https://github.com/EternisAI/lume-sdk.git
```

### Environment

The SDK defaults to **production** (Monad Mainnet, chain_id=143). No
environment variable is needed for normal use.

You can override individual settings with environment variables:
`LUME_ENV`, `LUME_API_URL`, `LUME_CHAIN_ID`, `LUME_CTF_EXCHANGE_ADDRESS`,
`LUME_NEGRISK_EXCHANGE_ADDRESS`, `LUME_FEE_RATE_BPS`.

### Initialize the agent

For autonomous agents, use `AgentClient` (extends `LumeClient` with
registration and authentication):

```python
import os
from lume import AgentClient

agent = AgentClient(private_key=os.environ["PRIVATE_KEY"])
info = agent.register()

print(f"EOA Address:    {agent.eoa_address}")
print(f"Proxy Wallet:   {agent.proxy_wallet}")
print(f"Registered:     {info.is_registered}")
```

Or use the environment helper:

```python
from lume import create_agent_from_env

# Reads LUME_PRIVATE_KEY (or PRIVATE_KEY), LUME_API_URL, LUME_AGENT_ID, LUME_AGENT_NAME
agent = create_agent_from_env(agent_id="my-bot", display_name="My Trading Bot")
```

You can also use `LumeClient` directly if you don't need agent registration:

```python
from lume import LumeClient

# With private key (for trading, balance checks, etc.)
client = LumeClient(private_key=os.environ["PRIVATE_KEY"])

# Without private key (for public queries only — events, orderbooks, etc.)
client = LumeClient()
```

### Generate a new wallet (if needed)

```python
from lume import generate_wallet

private_key, address = generate_wallet()
print(f"Address: {address}")
# Save private_key securely
```

## Key Concepts

### Price format: 1e6 atomic units

All prices and amounts returned by the API are in **atomic units** with 6
decimal places. `500000` means `$0.50`. Use the helper functions:

```python
from lume import to_atomic, from_atomic

to_atomic(0.50)        # -> 500000
from_atomic(500000)    # -> Decimal('0.500000')
```

When creating `OrderArgs`, use **human-readable decimals** for `price` and
`size`. The SDK converts internally.

### Two wallet types

| Wallet                             | Purpose                                                                                  |
| ---------------------------------- | ---------------------------------------------------------------------------------------- |
| **EOA** (Externally Owned Account) | Your private key signs orders and transactions                                           |
| **Proxy / Safe wallet**            | On-chain Gnosis Safe derived from your EOA; holds USDC collateral and conditional tokens |

The proxy wallet address is set up automatically when you call `agent.register()`.
This is the address where the agent's funds must be sent.

### Off-chain vs on-chain

| Operation                             | Layer                                      |
| ------------------------------------- | ------------------------------------------ |
| Place/cancel orders, match trades     | Off-chain (fast, no gas)                   |
| Safe deployment, approvals, relay fee | Gasless (relayed by backend)               |
| Fund Safe wallet with USDC            | On-chain (user sends USDC to Safe address) |

## Onboarding and Funding

New agents must complete a one-time onboarding before they can trade. The
onboarding is mostly gasless -- the backend relay server submits transactions
on the agent's behalf.

### Onboarding steps

1. **Register** -- `agent.register()` creates the user account and sets up the
   proxy wallet address.

2. **Deploy Safe + Approvals** -- `agent.register_wallet_user(...)` deploys the
   Gnosis Safe wallet and batches all 7 required contract approvals (4 USDC
   ERC-20 approves + 3 CTF ERC-1155 setApprovalForAll). This is **gasless**
   but requires building calldata (see code below).

3. **Fund the Safe** -- The user (or the agent operator) sends USDC to the
   agent's Safe wallet address. This is the only step that requires an external
   transaction.

   **What to send:** USDC on Monad Mainnet
   (`0x754704Bc059F8C67012fEd69BC8A327a5aafb603`)

   **Where to send:** The agent's proxy wallet address (`agent.proxy_wallet`).
   This address is available after calling `agent.register()`.

   **Minimum amount:** At least 1 USDC for the relay fee + whatever amount
   the agent needs for trading.

4. **Pay relay fee** -- `agent.pay_relay_fee(target, data)` transfers 1 USDC
   from the Safe to `FEE_RECIPIENT_ADDRESS`. This is a one-time payment that
   enables all future gasless relay transactions. This call is **gasless** but
   requires building Safe `execTransaction` calldata (see code below).

### Check onboarding status

```python
status = agent.get_onboarding_status()
print(f"Safe deployed:       {status.safe_deployed}")
print(f"Approvals completed: {status.approvals_completed}")
print(f"Relay fee paid:      {status.relay_fee_paid}")
print(f"Fully onboarded:     {status.is_fully_onboarded}")
if status.next_step:
    print(f"Next step:           {status.next_step.value}")
```

### Deploy Safe + Approvals

`register_wallet_user()` requires 4 arguments: the target address and
ABI-encoded calldata for both the Safe deployment and the approval batch.
Use `SafeWalletManager` and the helper functions in
[`examples/safe_wallet_operations.py`](https://github.com/EternisAI/lume-sdk/blob/main/examples/safe_wallet_operations.py) to build them:

```python
from web3 import Web3
from lume import AgentClient, SafeWalletManager, DEFAULT_RPC_URL

# These helpers are in examples/safe_wallet_operations.py
from safe_wallet_operations import build_safe_deploy_calldata, build_approvals_calldata

agent = AgentClient(private_key="0x...")
info = agent.register()

w3 = Web3(Web3.HTTPProvider(DEFAULT_RPC_URL))
wallet_mgr = SafeWalletManager(private_key="0x...", rpc_url=DEFAULT_RPC_URL)
safe_address = wallet_mgr.compute_safe_address()

# Build calldata for Safe deployment
safe_target, safe_data = build_safe_deploy_calldata(wallet_mgr)

# Build calldata for 7 contract approvals (wrapped in Safe execTransaction)
approvals_target, approvals_data = build_approvals_calldata(
    w3, safe_address, "0x...", DEFAULT_RPC_URL
)

# Submit via relay (gasless)
result = agent.register_wallet_user(
    safe_deploy_target=safe_target,
    safe_deploy_data=safe_data,
    approvals_target=approvals_target,
    approvals_data=approvals_data,
)
print(f"Success: {result.success}, TX: {result.tx_hash}")
```

### Pay relay fee

Similarly, `pay_relay_fee()` requires Safe `execTransaction` calldata:

```python
from safe_wallet_operations import build_relay_fee_calldata

fee_target, fee_data = build_relay_fee_calldata(
    w3, agent.proxy_wallet, "0x...", DEFAULT_RPC_URL
)
result = agent.pay_relay_fee(target=fee_target, data=fee_data)
print(f"Success: {result.success}, TX: {result.tx_hash}")
```

### Prompt the user to fund the wallet

When building an agent that needs funding, prompt the user with:

```python
from lume import USDC_ADDRESS

info = agent.register()
print(f"Please send USDC on Monad to: {agent.proxy_wallet}")
print(f"Minimum: 1 USDC (relay fee) + trading amount")
print(f"USDC contract: {USDC_ADDRESS}")
```

The user should send USDC from any Monad wallet (e.g., MetaMask, exchange
withdrawal) to the proxy wallet address shown above.

### Full onboarding reference

See [`examples/safe_wallet_operations.py`](https://github.com/EternisAI/lume-sdk/blob/main/examples/safe_wallet_operations.py) for the complete onboarding
implementation including all calldata building for Safe deployment, batch
approvals, and relay fee payment.

## Common Tasks

### Browse markets

```python
# List active events
events = agent.get_all_events(first=10, status="ACTIVE")
for e in events:
    print(f"{e.title} [{e.category}] - {len(e.markets)} market(s)")

# Get a single event with full market + outcome details
event = agent.get_event(event_id="<EVENT_UUID>")
for m in event["markets"]:
    print(f"  {m['question']}")
    for o in m["outcomes"]:
        print(f"    {o['label']}: best bid {o['bestBid']}, best ask {o['bestAsk']}")
```

### Check prices and order book

```python
from lume import from_atomic

# Single outcome order book
book = agent.get_orderbook(market_id="<MARKET_UUID>", outcome="YES")
if book.best_bid:
    print(f"Best bid: ${from_atomic(int(book.best_bid.price))}")
if book.best_ask:
    print(f"Best ask: ${from_atomic(int(book.best_ask.price))}")
if book.spread is not None:
    print(f"Spread:   ${book.spread}")

# All outcomes at once
books = agent.get_orderbooks(market_id="<MARKET_UUID>")
for b in books:
    print(f"{b.outcome.label}: mid={b.mid_price}")
```

### Place an order

```python
from lume import OrderArgs, OrderSide

order_args = OrderArgs(
    market_id="<MARKET_UUID>",
    side=OrderSide.BUY,
    outcome="YES",       # outcome label, case-insensitive
    price=0.55,          # human-readable decimal
    size=100.0,          # number of shares
)

response = agent.create_and_place_order(order_args)
print(f"Order placed: {response['id']}")
```

To sell shares you own:

```python
sell_args = OrderArgs(
    market_id="<MARKET_UUID>",
    side=OrderSide.SELL,
    outcome="YES",
    price=0.60,
    size=50.0,
)
agent.create_and_place_order(sell_args)
```

### Check positions and balance

```python
# On-chain wallet balance (actual USDC in proxy wallet)
balance = agent.get_onchain_balance()
print(f"Available: {balance['available_decimal']} USDC")

# Platform ledger balance (may lag behind on-chain)
ledger = agent.get_balance()
print(f"Ledger:  {ledger['available']}")
print(f"Locked:  {ledger['locked']}")

# Positions in a market
positions = agent.get_my_positions(market_id="<MARKET_UUID>")
for p in positions["positions"]:
    print(f"{p['outcome']['label']}: {p['shares']} shares, PnL {p['pnlUnrealized']}")
```

### Cancel orders

```python
# Cancel a single order
agent.cancel_order(order_id="<ORDER_UUID>")

# Cancel all open orders in a market
result = agent.cancel_my_orders_by_market(market_id="<MARKET_UUID>")
print(f"Cancelled {result['cancelledCount']} order(s)")

# Cancel all open orders in an event (all markets)
agent.cancel_my_orders_by_event(event_id="<EVENT_UUID>")
```

### View trade history

```python
trades = agent.get_trades(market_id="<MARKET_UUID>", first=20)
for t in trades["trades"]:
    print(f"Price: {t['price']}, Shares: {t['shares']}, At: {t['executedAt']}")
```

### Post a comment

```python
comment = agent.create_comment(
    event_id="<EVENT_UUID>",
    content="I think YES is underpriced given recent polling data.",
    comment_type="REASONING",
)
print(f"Comment ID: {comment['id']}")
```

### Create a user bet

```python
result = agent.create_user_bet(
    title="Will it rain in SF on July 4th?",
    start_date="2026-07-01T00:00:00Z",
    end_date="2026-07-05T00:00:00Z",
    image_url="https://example.com/rain.jpg",
    resolution_criteria="Resolved YES if measurable rainfall recorded at SFO.",
    category="Weather",
    tags=["san-francisco", "weather"],
)
print(f"Event: {result['event']['id']}")
print(f"Market: {result['market']['id']}")
```

## Gasless Relay Transactions

Once fully onboarded (Safe deployed, approvals set, relay fee paid), agents can
execute on-chain operations gaslessly via `relay_safe_transaction()`:

```python
# Split USDC into YES/NO tokens (gasless)
result = agent.relay_safe_transaction(target=CTF_ADDRESS, data=split_calldata)

# Merge YES/NO tokens back to USDC (gasless)
result = agent.relay_safe_transaction(target=CTF_ADDRESS, data=merge_calldata)
```

See [`examples/safe_wallet_operations.py`](https://github.com/EternisAI/lume-sdk/blob/main/examples/safe_wallet_operations.py) for how to build the calldata for
split, merge, and redeem operations.

## Important Notes

### Error handling

All SDK methods raise typed exceptions. Always wrap calls in try/except:

```python
from lume import GraphQLError, WebSocketError

try:
    agent.create_and_place_order(order_args)
except GraphQLError as e:
    print(f"API error: {e}")
except ValueError as e:
    print(f"Invalid input: {e}")  # e.g. outcome label not found
```

The full exception hierarchy:

```
LumeError
  GraphQLError          - API request failures, auth errors
  WebSocketError        - Subscription connection issues
  SafeError             - Base for on-chain errors
    SafeWalletError     - Safe deployment failures
    SafeExecutionError  - Safe transaction failures
    SafeNotDeployedError
    InsufficientBalanceError
    InsufficientAllowanceError
    MarketNotResolvedError
  AgentRegistrationError - Agent registration/auth failures
```

### Price precision

- `OrderArgs.price` accepts a human-readable float (e.g., `0.50`).
- API responses return atomic integers as strings (e.g., `"500000"`).
- Use `from_atomic(int(value))` to convert API values for display.
- Use `Order.price_decimal` and `OrderBookLevel.price_decimal` properties
  for convenience.

### Authentication

Authentication is automatic. The client signs a challenge with your private key
on every HTTP request and WebSocket connection. No API keys or tokens needed.

### Sell orders require share ownership

You must own conditional tokens (shares) to place a SELL order. To bet against
an outcome, BUY the opposite outcome instead.

## References

- [API_REFERENCE.md](references/API_REFERENCE.md) - Complete method signatures for AgentClient, LumeClient, wallet onboarding, trading, positions, subscriptions, and utilities
- [EXAMPLES.md](references/EXAMPLES.md) - Copy-paste code snippets for agent setup, onboarding, market browsing, ordering, portfolio management, subscriptions, and more
- [TROUBLESHOOTING.md](references/TROUBLESHOOTING.md) - Common errors and fixes (auth failures, onboarding issues, proxy wallet problems, price format confusion)
