how interlock works
A model writes trade proposals. A pure function decides them. Everything below is either arithmetic you can re-run or a live read you can check yourself.
Overview
Interlock is an AI trading agent for tokenized stocks on Solana with one unusual property: it cannot decide anything. The model's output is a request. The decision is made by lib/policy.ts — a pure function with no clock, no network, and no model inside it.
That separation is the entire safety story. A model can be confident and wrong, or steered by whatever it just read. None of that reaches your money if the thing holding the trigger is arithmetic.
The loop
- 1You set six numbers — the policy.
- 2The agent reads live prices for the symbols you allow and writes one proposal with a thesis.
- 3The engine runs every rule and stamps ALLOW or REFUSE, naming the line that decided it.
- 4You tighten a rule and the same proposal is re-judged instantly — in your browser, by the same function.
The six rules
verdict = f(proposal, policy, spentTodayUsd) symbol ∈ policy.allowedSymbols SPYx, QQQx, GLDx side ∈ policy.allowedSides buy 0 < size ≤ policy.maxSizeUsd $500 confidence ≥ policy.minConfidence 0.62 thesis.len ≥ policy.minThesisChars 180 spent+size ≤ policy.dailyBudgetUsd $2000
- ·Symbols are an allowlist, never a blocklist. A ticker that isn't named is refused — including ones that didn't exist when you wrote the rule.
- ·The budget counts today's spend. It's passed in, not read from a clock, so the same inputs always give the same verdict.
- ·Every failing rule is reported — not just the first one.
Edges
A proposal that passes by sitting exactly on a limit is stamped EDGE. It's still an ALLOW — you authorized it — but a rule you only just cleared is a rule worth re-reading. The engine also exposes the weakest proposal your policy would allow: max size, minimum confidence, minimum thesis. Not a suggestion — a warning about the floor you've set.
The adversary
A second model is told your policy and asked for the worst trades it still permits. Its attempts go through the same engine, in public. Whatever gets through is not a flaw in the engine — it's the floor of what you allowed. The fix is always to tighten the rules, never to argue with the model.
attack my rules →API reference
All endpoints return JSON. The verdict is the same function the UI runs.
/api/decideRule on a proposal. No model involved — pure arithmetic, so anyone can audit a verdict without trusting our UI.
{
"proposal": { "symbol": "SPYx", "side": "buy",
"sizeUsd": 200, "confidence": 0.8,
"thesis": "…" },
"policy": { "maxSizeUsd": 500 },
"spentTodayUsd": 0
}
→ { "verdict": { "decision": "ALLOW", "checks": [...],
"failed": [], "edges": [], "reason": "…" } }/api/proposeThe agent writes one proposal under your policy, priced from the live market — then the engine rules on it.
{ "policy": { "allowedSymbols": ["SPYx"] } }
→ { "proposal": {...}, "verdict": {...}, "market": [...] }/api/probeThe adversary hunts for the weakest trades your policy still allows, and the engine rules on each attempt.
{ "policy": { "minConfidence": 0.5 } }
→ { "floor": {...}, "attempts": [...],
"gotThrough": 2, "refused": 1 }/api/stocksThe 59 verified tokenized stocks, priced live. Anything unpriced is labelled, not quietly counted.
→ { "stocks": [ { "symbol": "SPYx", "name": "S&P 500",
"mint": "Xso…", "priceUsd": 773.83 } ], … }Honesty & safety
- ·Nothing is executed. Interlock decides; it does not trade for you. When execution ships, it ships behind these same rules.
- ·Non-custodial. Connecting a wallet only reveals your address.
- ·Real or zero. Counters that need real signed verdicts stay at zero until they exist.
- ·One official address. $ILOCK's contract appears only on the token page and @interlocklat on X — anywhere else is a fake, however early it appeared.