Polydesk


Eight AI agents on a visual canvas that analyse prediction markets and DeFi positions, propose trades, and execute them under risk limits.

Status

A working prototype, built in five weeks in spring 2026. The product, the agents' analysis and the transaction builders are real. The automatic execution path is only partly connected, and I list exactly where below. The demo at polydesk.net runs on sample data with no trading keys and executes nothing.

RoleYearKindTry it
Concept, product and brand design, engineering2026AI agents, tradingpolydesk.net
8agents: four for prediction markets, four for DeFi
324commits between 19 March and 25 April 2026
128backend test functions in 16 files

The problem

Prediction markets move on news before most traders have read it, and DeFi positions need watching around the clock. The tools for both assume a person at a screen. An agent can watch, but letting an agent spend money needs three things most demos skip: a reason a person can read, a limit the agent cannot argue with, and a clear line between proposing a trade and making it.

What I built

  • Eight agents with one shape. Each agent takes a market or a position and returns the same thing: a recommendation, a confidence between 0 and 1, the reasoning in words, and the signals behind it. Four work on Polymarket (Analyst, Scout, Momentum, Sentinel) and four on DeFi (Yield Farmer, Liquidation Guardian, Arbitrageur, Airdrop Hunter).
  • A canvas as the workspace. Wallets, markets, protocols, agents and results are nodes. You drag a market on, attach an agent, chain agents together, and watch results arrive. Nine templates and a demo mode load a working desk.
  • No wallet needed to start. You sign in with an email, Google or a social account, and a wallet is created for you. People who already have a wallet connect it instead.
  • Two ways to execute, and a third half-built. By default the person signs every trade in their own wallet and the server never holds a key. A second mode keeps an encrypted key on the server and signs for you. A third, signing through a Coinbase MPC wallet so no key is held at all, is written but not connected.
  • Transaction builders for six protocols. Aave v3, Compound v3, Lido, Jupiter, Marinade and marginfi, each producing real calldata.
  • A news pipeline feeding the agents. Twelve scheduled jobs pull news, social posts, market snapshots, protocol yields and oracle prices, then classify and score them.
  • The product around it. Sign-in with email or a wallet, card funding, a Telegram bot for alerts, billing, a trader leaderboard, and the brand.

How it is structured

A trade is proposed by an agent, checked by code, and signed by the person or with a stored key. The agent itself never holds a key.

Signing in without a wallet

Most crypto products lose people at the first screen, which asks for a wallet they do not have. Polydesk uses Privy for sign-in, set to create an embedded wallet for anyone who arrives without one.

StepWhat happens
Sign inEmail, Google, X, Discord, Farcaster, or an existing wallet
WalletCreated on first login for users without one. Polygon is the default chain; Ethereum, Arbitrum, Optimism and Base are enabled
SessionThe interface sends its Privy token to the API, which looks the user up with Privy and issues its own session token
Own walletSign-In with Ethereum: the server issues a one-time nonce, the wallet signs a message containing it, and the server checks the signature and retires the nonce
FundingA card on-ramp (MoonPay) in the interface, or a transfer from another wallet

How a trade reaches the chain

VenueHow the transaction is builtHow it is signed and sent
PolymarketAn order for the central limit order book, on Polygon, placed through the user's Polymarket proxy walletManual: the person signs in the browser. Automatic: the server signs with the user's stored Polymarket credentials and posts the order
Aave v3, Compound v3, LidoABI-encoded calldata for supply, withdraw, repay or stake. An approve is added only when the current allowance is too smallGas is estimated with a 20% margin; the transaction is signed, sent, and waited on for a receipt
Jupiter, Marinade, marginfi (Solana)Jupiter returns a quote and then a serialized transaction for that route, with a slippage limit of 0.5% by defaultSigned with the user's keypair and sent

Multi-step actions are built as a list and run in order, stopping at the first failure: approve, then supply, for example. Every transaction is written to the database as pending before it is sent and updated with the hash and the outcome after.

The Liquidation Guardian has three thresholds on a lending position's health factor: warn at 1.3, repay a quarter of the debt at 1.15, repay half at 1.05.

In the code

Private repository

These are short excerpts from Beach-Bum/Polydesk, which is private.

base.py
sentinel.py
executor.py
encryption.py
scheduler.py

Every Polymarket agent returns this. reasoning is what the person reads on the canvas before approving; signals is the same judgement as data.

backend/agents/polymarket/base.py
@dataclass
class AgentAnalysis:
    """Output of an agent's analysis step."""
    market_id: str
    agent_type: str
    recommendation: str  # BUY_YES, BUY_NO, SELL_YES, SELL_NO, HOLD, EXIT
    confidence: float    # 0-1
    reasoning: str       # Human-readable explanation
    signals: dict = field(default_factory=dict)  # Structured signal data
    suggested_size: float = 0.0   # Suggested position size in USDC
    suggested_price: float = 0.0  # Suggested entry/exit price

The limits sit in the executor, not in the agent, so no agent can talk its way past them. A blocked trade is logged with the reason.

backend/agents/polymarket/executor.py
@dataclass
class RiskLimits:
    """Per-agent risk controls."""
    max_bet_usd: float = 100.0
    daily_loss_limit_usd: float = 500.0
    max_open_positions: int = 10

def check_risk_limits(self, request: TradeRequest, deployment_id: str) -> str | None:
    if request.size > self.risk_limits.max_bet_usd:
        return f"Trade size ${request.size:.2f} exceeds max bet ${self.risk_limits.max_bet_usd:.2f}"
    ...
    if daily_pnl < -self.risk_limits.daily_loss_limit_usd:
        return f"Daily loss limit reached ..."

The Sentinel agent is plain arithmetic, with no model in it: a stop-loss and a trailing stop.

backend/agents/polymarket/sentinel.py
self.stop_loss_pct = self.config.get("stop_loss_pct", 0.20)          # 20% loss = exit
self.trailing_stop_pct = self.config.get("trailing_stop_pct", 0.15)  # 15% from high

stop_loss_triggered = pnl_pct <= -self.stop_loss_pct
trailing_stop_triggered = drawdown_from_high >= self.trailing_stop_pct and hwm > entry_price

Where a model is used, and where it is not

StepDone byWhy
Classifying a news itemA modelReading language is what it is for
Estimating a probabilityA model, in five fixed steps: decompose, base rates, key factors, weigh evidence, calibrateThe steps make the reasoning inspectable
Finding related marketsLocal embeddings and a vector storeNo model call, so it is fast and costs nothing per search
Stop-loss, trailing stop, health factorArithmeticA rule about money should give the same answer every time
Risk limitsCode in the executorThe agent proposing a trade must not be the one that allows it
SigningThe person's wallet by defaultThe server should not hold a key it does not need

The stack

PartBuilt with
InterfaceReact 19, TypeScript, Vite, a node canvas (@xyflow/react)
Wallets and sign-inPrivy, wagmi, viem
APIFastAPI, SQLAlchemy, PostgreSQL
Agents and pipelinePython, the Claude API, ChromaDB with local sentence embeddings
ChainPolymarket's order book client, web3.py, solders, Coinbase AgentKit
PricesPyth, Chainlink, Birdeye, DeFiLlama, behind one oracle with a 10-second cache

About 25,000 lines of Python and 47,000 of TypeScript.

What a DeFi engineer would find

I read the execution code line by line before writing this page. These are the things I would expect a reviewer to raise, most serious first.

Not connected

  • MPC signing is never called. Launching an automatic strategy creates a Coinbase MPC wallet and stores its id, and the executor has a function to sign with it. Nothing passes the id to the executor, so automatic execution always takes the stored-key path.
  • The Liquidation Guardian does not watch the chain. The code to read a live health factor exists and is used by the wallet scan. The scheduled job that runs the guardian reads the health factor saved when the agent was deployed, so it re-checks an old number every five minutes.
  • Arbitrage is one leg, on one chain. The scanner finds round-trip spreads on Solana and builds a single swap. The EVM scanner returns nothing, and the cross-chain scan compares oracle prices without costing the bridge or the fill. Nothing is atomic.

Security

  • One of the two key-encryption modules falls back to a default key if its setting is missing. The other refuses to start in production without one. Both should refuse.
  • The encryption is labelled AES-256 and is Fernet, which is AES-128 with an HMAC. Sound, but mislabelled.

Risk limits

  • Three of five DeFi limits are never read. Position size, daily loss and slippage are declared; the executor checks only the allowed protocols and chains.
  • The Polymarket position limit is never read, and the daily loss limit is really a daily net-spend limit: it adds up buys and sells, not realised losses.

Transaction handling

  • A Solana transaction is reported as successful if it is still unconfirmed after 30 seconds, and a confirmed-but-failed one is not told apart from a good one.
  • EVM transactions use a legacy gas price, take the nonce from the latest block and not the pending one, are not simulated before sending, and leave the ETH value out of the gas estimate, so a payable call falls back to a fixed gas limit.
  • A failed position read returns a health factor of 999, the same value used for "no debt", so an RPC error looks like safety.

Evidence

  • The interface has no tests. All 128 test functions are on the backend, and none exercises a transaction against a fork or a test network.
  • The backtest has no recorded result, so I state no accuracy.
  • I have not placed a live order while writing this.

What I would do first: connect the MPC path and delete the stored-key mode, make the guardian read the chain, enforce every declared limit in the executor, and run every transaction builder against a forked mainnet in the tests.

Open questions

More

The demo

Try Demo opens a desk with sample markets, agents and results. Nothing is executed.

Open ↗
Project notes on the weblog
Open ↗