Wheel Desk started with a familiar mess. The wheel is one of the most mechanical strategies in options trading: sell a cash-secured put, take the shares if you're assigned, sell covered calls against them, close, and repeat. Running it, though, means living in three places at once — a broker tab for live prices, a scanner for finding contracts, and a spreadsheet of credits, collateral, and P&L that nobody fully trusts. The brief was simple: one screen for every turn of the wheel.

We wrote the trader's rules down before writing any code. Sell puts around a 0.25–0.30 delta, 30 to 45 days out. Take profits at 50% of the credit. Don't hold a contract through earnings. Those rules became editable settings rather than copy in the interface, and they drive everything downstream: which contracts appear, how large a position can be, and when a trade is flagged as done. A wheel tool is only useful if it applies the same rules every time, so the rules had to live in data, not in someone's head.

The architecture is a small monorepo with hard boundaries. A React and Vite front end with Tailwind and shadcn-style components handles the interface. A Fastify API is the only service allowed to talk to Tradier, the market-data provider, so the API token never reaches a browser. A shared package holds Zod contracts and all of the option math — credit received, collateral, unrealized and realized P&L, percent of max profit, affordable contracts — with unit tests, because those numbers have to match on every screen. Supabase provides Postgres and passwordless magic-link sign-in.

Every table has row-level security, and every policy compares the row's owner to the signed-in user. The API never uses a service-role key: it creates its database client with the caller's own access token, so even a bug in a route handler can't read another trader's positions. For a product that holds people's trading records, we wanted that guarantee to come from the database itself, not from careful code review.

Honesty about data was a design rule too. Marks use the bid/ask midpoint and fall back to the last trade. If market data is unavailable, the interface shows a dash instead of inventing a price, and the trader can enter a manual mark. Dates and days to expiration share one timezone boundary, so a position never shows two different DTEs on two screens. The 'credit at max' column is labeled as exactly what it is — the opening credit if every put expires out of the money — not a promise.

The shortlist is where Wheel Desk earns its place. It pulls option chains for the trader's watchlist, keeps only contracts inside their delta band and DTE window, drops anything their cash can't cover, filters out scheduled earnings, and ranks what's left by return on collateral. Top Picks goes further with a deterministic scoring pipeline: moving averages and Bollinger Bands from daily closes, liquidity filters on spread, open interest, and volume, then a weighted score with rule-generated reasons like 'near 50-day support'. The weights live in one config object, so every ranking can be explained and tested.

We were deliberate about where AI belongs. The spec has one line we keep coming back to: never let the model choose, rank, or size. The ranking is code. The most a language model is allowed to do is write one plain sentence explaining a pick from the stored fields, without adding numbers that aren't there — and if no model is available, a template joins the reason tags instead. Wheel Desk doesn't place trades, connect to a broker, or tell anyone what to buy. It organizes the numbers so the trader can decide.

We built it spec-first, with the spec written as a hand-off document for coding agents: a locked architecture, acceptance tests, and explicit non-goals. That's how it went from first commit to a public beta in under two weeks, deployed on Vercel with the web app and API as separate projects. Position tabs, premium history from seven days to a contract's full lifetime, closed-trade history, and Top Picks all shipped in that window. Wheel Desk is live at wheel-desk.com and free during the beta.