Skip to main content
Heartbeat is the per-thesis monitor loop. It controls how often SimpleFunctions scans news and social context for a thesis, which model tier evaluates new evidence, the monthly cost ceiling, and whether the monitor is allowed to create closed-loop entry or exit intents. Heartbeat work is independent of thesis lifecycle status. A thesis can be active while its heartbeat is paused, and pausing the heartbeat never archives or closes the thesis.

CLI

# show config + this-month cost summary
sf heartbeat <thesis-id>
sf heartbeat <thesis-id> --json

# update fields (any combination)
sf heartbeat <thesis-id> --news-interval 60      # minutes, 15-1440
sf heartbeat <thesis-id> --x-interval 240        # minutes, 60-1440
sf heartbeat <thesis-id> --model base            # cheap | base | medium | heavy
sf heartbeat <thesis-id> --budget 15             # USD per month, 0 = unlimited

# pause / resume
sf heartbeat <thesis-id> --pause
sf heartbeat <thesis-id> --resume

# closed-loop intent creation
sf heartbeat <thesis-id> --closed-loop-entry
sf heartbeat <thesis-id> --no-closed-loop-entry
sf heartbeat <thesis-id> --closed-loop-exit
sf heartbeat <thesis-id> --no-closed-loop-exit

API

GET   /api/thesis/{id}/heartbeat
PATCH /api/thesis/{id}/heartbeat
Auth: Authorization: Bearer sf_live_... (or browser session). 404 if the thesis isn’t owned by the caller.

GET response

{
  "thesisId": "thesis_abc123",
  "config": {
    "mode": "active",
    "newsIntervalMin": 240,
    "xIntervalMin": 240,
    "evalModelTier": "cheap",
    "monthlyBudgetUsd": 15,
    "paused": false,
    "smartModel": true,
    "closedLoop": { "entry": false, "exit": false }
  },
  "defaults": { "newsIntervalMin": 240, "xIntervalMin": 240, "evalModelTier": "cheap", "monthlyBudgetUsd": 15, "smartModel": true, "...": "..." },
  "costs": {
    "monthlyTotal": 2.4831,
    "llmCalls": 18,
    "searchCalls": 6,
    "inputTokens": 84210,
    "outputTokens": 11034,
    "budgetRemaining": 12.5169
  }
}

PATCH body

All fields optional. Any combination is accepted; unknown fields are ignored. 400 No valid fields to update if nothing recognised is sent.
FieldTypeDefaultRange / valuesNotes
newsIntervalMinnumber24015 – 1440Minutes between news/context scans.
xIntervalMinnumber24060 – 1440Minutes between social/X scans.
evalModelTierstring"cheap"cheap, base, medium, heavyModel tier for the evaluation step.
monthlyBudgetUsdnumber15>= 0 (0 = unlimited)Monthly LLM + search ceiling. Heartbeat auto-pauses when exceeded.
pausedbooleanfalsePauses the loop without changing thesis lifecycle. Server tags the pause as manual so it does not auto-resume next month.
smartModelbooleantrueRun cheap by default, auto-escalate to medium on a significant change (confidence delta > 3%, kill condition, or node prob shift > 15%). Forces a medium deep eval at least every 24 h.
closedLoopboolean | object{ entry: false, exit: false }true ⇒ both, false ⇒ neither, or { entry, exit }Allow the monitor to create entry / exit intents. Booleans inside the object are individually validated.

PATCH response

{
  "thesisId": "thesis_abc123",
  "config": { "...": "merged config" },
  "updated": ["newsIntervalMin", "evalModelTier"]
}

Errors

StatusBody errorCause
400newsIntervalMin must be 15-1440Out-of-range value.
400xIntervalMin must be 60-1440Out-of-range value.
400evalModelTier must be cheap, base, medium, or heavyInvalid tier.
400monthlyBudgetUsd must be >= 0Negative budget.
400closedLoop must be boolean or { entry, exit }Wrong shape.
400closedLoop.entry must be boolean / closedLoop.exit must be booleanWrong member type.
400No valid fields to updateBody had no recognised fields.
401Unauthorized. Provide a valid API key (Bearer sf_live_xxx) or session.Missing / invalid auth.
404Thesis not foundThesis does not exist or does not belong to the caller.

Curl

# read
curl -H "Authorization: Bearer $SF_API_KEY" \
  "https://simplefunctions.dev/api/thesis/thesis_abc123/heartbeat"

# update
curl -X PATCH \
  -H "Authorization: Bearer $SF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"newsIntervalMin": 60, "evalModelTier": "base"}' \
  "https://simplefunctions.dev/api/thesis/thesis_abc123/heartbeat"

What heartbeat is not

  • Not an order router. It can write evaluations, signals, alerts, and (when closedLoop is enabled) execution intents. Orders still go through the intent / runtime / risk-gate path.
  • Not the same as thesis lifecycle status. To archive, close, or publish a thesis, use the Thesis API. To stop background evaluation only, set paused: true here.
  • Not a global setting. Each thesis has its own heartbeat config, and the dashboard / CLI lets you tune them independently.

Next steps

Thesis API

Full thesis lifecycle HTTP surface.

Portfolio autopilot

Separate portfolio-tick loop and risk gates.