The 60-second version
policy.yaml is one small file that answers one question: what is my agent allowed to do with my money? Eight sections — funding, instruments, caps, tickers, hours, approval, circuit breaker, and news handling — each a hard limit the Agent Firewall enforces on every order. If you’ve generated a config with the Safety Kit, you already know the rules; this is the same policy in machine-readable form, with the enforcement semantics spelled out.
The design principle behind every field: the policy constrains how much an agent can do, never what to buy. Nothing in this file is trading advice — it’s a blast-radius contract.
The file at a glance
version: 1 funding: 2000 # the denominator for every percentage below instruments: allow: [equities] caps: per_trade_pct: 10 daily_volume_pct: 40 concentration_pct: 35 tickers: allowlist: [] denylist: [TSLA, GME] hours: window: "10:00-15:30" timezone: America/New_York approval: require_above_pct: 15 circuit_breaker: max_trades: 5 per_minutes: 10 news: advisory_only: true
funding — the denominator
Every percentage in the file is computed against this number, not against your live account balance. That’s deliberate: if caps floated with the balance, a winning streak would silently raise your risk limits and a losing streak would tighten them mid-incident. Fixed-denominator caps mean the policy you reviewed is the policy that runs. When you add money, you update funding yourself — a deliberate, logged policy change.
instruments — the scope fence
The bluntest and most important rule. allow: [equities] means the agent’s tool surface simply does not include options, margin, crypto, or — critically — fund transfers, regardless of what the underlying broker MCP server exposes. The firewall enforces this at the tool level: out-of-scope tools are not blocked when called, they are never advertised to the agent at all. An agent can’t be talked into using a tool it cannot see.
caps — the three blast-radius numbers
per_trade_pct— max order value, as a percent of funding. The check is arithmetic on the structured order:qty × price ≤ funding × pct. For market orders the firewall prices the check at the current quote plus a slippage buffer, so "buy 10,000 shares at market" can’t sneak under a stale price.daily_volume_pct— total traded value per rolling day, buys and sells both. This is the anti-churn rule: it bounds how much damage repetition can do even when every individual trade is small. The counter resets at market open in your configured timezone, and the firewall persists it across restarts — bouncing the process does not refill the budget.concentration_pct— max position in any single ticker, checked against post-trade state: current holding plus the pending order. This is the rule that catches the slow version of a pump-and-dump steer — twenty small in-cap buys of the same ticker hit the concentration wall even though each one passes the per-trade check.
The Safety Kit tiers map to these caps as: conservative 5/15/20, balanced 10/40/35, aggressive 25/100/60 (per-trade / daily / concentration, all percent of funding). Aggressive is not "no limits" — it’s limits you chose.
tickers — allowlist and denylist
Two modes with different security postures. Allowlist (allowlist: [AAPL, MSFT, VOO]) is default-deny: the agent trades only what you pre-approved, which neutralizes fake-ticker attacks outright — a hallucinated or attacker-planted symbol isn’t on the list, end of story. Denylist is default-allow: everything except what you’ve banned. It’s looser by design and appropriate only when you accept the unknown-ticker risk. If both are set, the allowlist wins and the denylist is redundant. Matching is exact symbol match after normalization — no fuzzy matching, because fuzziness is exactly what ticker-confusion attacks exploit.
hours — the trading window
Orders outside window (evaluated in timezone, market holidays respected) are rejected. The point isn’t market mechanics — it’s that your agent trades when you’re awake to notice. A 3 a.m. flurry of activity is one of the highest-signal anomalies in any monitoring setup, and the cheapest way to be able to react to it is to have made it impossible.
approval — the human gate
Orders above require_above_pct aren’t rejected — they’re held. The firewall parks the order, notifies you (terminal prompt locally; phone push in Pro), and executes only on explicit approval. Held orders expire un-executed after a timeout (default 15 minutes) — an unanswered approval is a "no," because fail-closed applies to humans too. This single rule converts the worst-case scenario from "the agent moved most of my account" to "the agent asked, and I said no from my phone."
circuit_breaker — the loop killer
max_trades: 5 / per_minutes: 10 rejects the sixth order inside any rolling ten-minute window and — unlike every other rule — latches: once tripped, all write calls are rejected until you manually re-arm. A tripped breaker means something is wrong with the process (a retry loop, a runaway plan, scripted manipulation), not the individual trades, so the firewall refuses to let it continue at any pace. This rule exists because the most common real-world agent failure isn’t malice — it’s a loop: the agent treats an error as "order failed," retries, and the retries all succeeded. The breaker caps that disaster at five.
news.advisory_only — the injection damper
When true, the firewall appends a structured notice to news/sentiment tool responses marking them as untrusted advisory data, and rejects any order whose stated rationale cites a news item as its sole trigger (Pro’s anomaly engine scores this; the free tier applies the marking only). This is the one rule that is honestly defense-in-depth rather than a guarantee — text influence on the model can’t be fully policed from outside. The guarantees come from the caps: even a fully headline-poisoned agent is still trading inside your per-trade, daily, and concentration walls.
Evaluation order
Every write call runs the full pipeline in fixed order: kill switch → instrument scope → ticker rules → hours → per-trade cap → daily volume → concentration → circuit breaker → approval gate. First failure wins, evaluation stops, and the decision plus the failing rule is written to the audit log and returned to the agent as a structured error. Deterministic order matters for auditability: the same attempt always fails the same way, so your logs are comparable across days and versions.
Two engineering notes that round out the semantics. Atomicity: the daily-volume and circuit-breaker counters update atomically with order submission, so an agent firing parallel orders can’t race past a cap. Fail-closed parsing: a malformed policy file doesn’t fall back to defaults — the firewall refuses to start. A typo in your safety config should never silently mean "no rules."
Treat it like production config
The file is small on purpose: eight sections, every one auditable in a two-minute read. Keep it in version control, diff every change, and re-run the block test after editing. Your policy is your risk appetite, written down — the firewall just makes it non-negotiable.
The firewall beta ships to the waitlist first. Join it →