Autonomous systems
Scout · Valet · Vizier
A three-layer stack that lets an AI agent research the market, decide and place real orders — with the safety catch closed by default.

$2
the real order that proved 653 green tests weren't enough
- Conditions
- live account at Interactive Brokers · market order in AAPL
- Role
- Author, personal project
- Context
- Three public repositories, MIT license
- Period
- 2026
- Status
- Public · validated with a real order
The problem
Giving an AI agent access to a broker is easy. The hard part is making sure it doesn’t do something stupid with real money — and proving the guarantee works.
I split the system into three pieces that don’t mix. Scout only reads: 62 research tools covering stocks, ETFs, crypto, macro, SEC and on-chain data, all from free sources, with no ability to write at all. Valet is the only piece that touches the broker, and every order goes through a guard that is closed by default: without explicit authorization, the order doesn’t go out. Vizier decides — researches, sizes by conviction, carries the thesis across sessions and measures its own performance against the benchmark.
The decision that changed the project
I had 653 tests passing and green CI in all three repositories — the count as of July 2026, before the order. I sent a two-dollar order on a real account, just to see.
The order exposed a unit bug: the system treated a value in dollars as if it were a number of shares. On a sell, that would have placed a stop selling more stock than the portfolio held — a short position nobody asked for.
The tests didn’t catch it because the fakes lied: they answered in the format I expected, not in the format the broker actually returns. No amount of offline testing would have found it.
The result
The bug was fixed in the two affected repositories and became a recorded decision: integration is proven in production, with small amounts of money. Tests prove logic; they don’t prove you understood the other end.
The same principle took down another problem later — the server hung on the first call because the data libraries were blocking the async loop. The fix wasn’t to raise the timeout: it was to warm up the libraries at startup, attacking the cause.