Heartbeat engine

Your thesis runs while you sleep

Prices, news, signals, causal models — pulled every 15 minutes across Kalshi and Polymarket. One call returns everything that matters. Your agent pushes observations anytime.

1

Write a thesis in plain language

$ sf create "Iran war sustains oil above $100, recession by Q3"

✓ Causal tree built — 6 nodes

  n1  Hormuz closure persists       ████████░░ 85%
  n2  Oil sustained above $100      █████████░ 91%
  n3  Fed constrained by stagflation███████░░░ 72%
  n4  Consumer spending contracts   ██████░░░░ 65%
  n5  GDP contraction Q3            ██████░░░░ 63%
  n6  NBER declares recession       █████░░░░░ 55%

✓ 49 markets mapped across Kalshi + Polymarket
✓ 12 edges found — largest: WTI T150 +36¢
✓ Heartbeat started — next cycle in 15 min

Natural language becomes a causal tree of testable claims. Each node has a probability and maps to real contracts. The heartbeat starts immediately.

2

Every 15 minutes, autonomously

Heartbeat #847 — 11:14 UTC

[news] 3 queries — 2 regular, 1 adversarial
   WSJ: Hormuz effectively closed to tanker traffic
   Trump announces 5-day strike pause
   IEA: "major threat worse than 1970s oil shock"

[prices] 49 markets rescanned
  WTI T135  58¢ → 62¢  ▲ +4¢  signal injected
  WTI T150  36¢ → 38¢  ▲ +2¢
  Recession  32¢ → 35¢  ▲ +3¢  signal injected

[milestones] 3 upcoming
  18h  WTI weekly settle
  3d   OPEC emergency meeting
  5d   CPI May print

[eval] 5 signals consumed → confidence 89% ▲ +2
Kill conditions checked:
   Ceasefire deal signed       — no
   Hormuz reopens to tankers   — no
   Trump lifts Iran sanctions  — no
   Oil drops below $80         — no

Adversarial query: "iran ceasefire deal progress"
  → No credible path to resolution found

News scan, price rescan, milestone detection, kill condition check, adversarial search, LLM evaluation — all automatic. Signals that move prices by 3¢+ get injected. The LLM consumes them and updates the causal tree.

3

One call returns everything

$ sf context f582bf76 --json

{
  "confidence": 0.89,
  "confidenceDelta": 0.02,
  "nodes": [
    { "id": "n1", "label": "Hormuz closure persists", "prob": 0.85,
      "prevProb": 0.82, "reason": "WSJ confirms tanker blockade" },
    ...
  ],
  "edges": [
    { "market": "WTI T150 YES", "price": 38, "implied": 74,
      "edge": 36, "spread": 1, "depth": 2400,
      "liquidity": "high", "type": "consensus_gap" },
    ...
  ],
  "evaluation": {
    "summary": "Hormuz closure confirmed by WSJ...",
    "signalsConsumed": 5,
    "trackRecord": { "hitRate": 67, "edgesTracked": 12 }
  },
  "positions": [...],
  "updatedAt": "2026-03-23T11:14:00Z"
}

Causal tree with updated probabilities, edges with live prices and orderbook, evaluation summary, track record, positions — all in one response. Your agent doesn't assemble state. It reads it.

4

Your agent pushes back

# Your agent observes something the heartbeat missed
$ sf signal f582bf76 "Brent just broke $100 — first time since 2022"

✓ Signal queued — type: user_note
  Will be consumed in next evaluation cycle

# Or force immediate evaluation when it matters
$ sf evaluate f582bf76

✓ Evaluation complete
  Confidence: 89% → 91% ▲ +2
  n2 (Oil above $100): 91% → 95%
  New edge surfaced: Brent T110 YES — +28¢

The heartbeat runs autonomously but your agent can inject observations anytime. Force an evaluation when something big happens — don't wait for the next cycle.

The heartbeat gives your agent context. What it does with that context is up to your execution strategy.