Skip to main content
The runtime is the long-running process that watches active intents and executes authorized workflows. It is the bridge between an analyst writing intents (CLI / API / agent) and orders actually leaving for Kalshi or Polymarket. For automated execution, prefer intents + runtime over raw sf buy / sf sell. Intents are persisted, replayable, race-free, and reviewable before execution.

Two ways to run it

ModeWhere it runsCredentialsBest for
LocalYour machine, foreground or backgroundLocal Kalshi / Polymarket private keys (file paths)Operators, dev, single-machine setups.
Cloud (BYOK)SimpleFunctions cloudEncrypted exchange credentials, connected by the user and never returned by the APIAlways-on automation without keeping a laptop awake.

Quick start (local)

sf setup                                # configure SimpleFunctions + Kalshi keys
sf intent buy KXRATECUT-26DEC31 10 \
  --trigger below:45 --rationale "edge below 45c"
sf runtime start --smart --daemon       # start watching, with LLM soft-condition support
sf runtime status --json

What runtime watches

Each tick (every 30 seconds) the runtime:
  1. Reads your active intents from GET /api/intents?status=....
  2. For each intent, checks the trigger — hard price/time triggers locally, soft NL conditions if --smart is enabled.
  3. Marks newly-firing intents armedtriggeredexecuting.
  4. Places the order on the configured venue using your local exchange keys.
  5. Tracks fills against the intent (filledQuantity), retries partial fills on the next tick.
  6. Writes structured status / errors to ~/.sf/runtime.log.
Runtime state files live under ~/.sf/:
FilePurpose
~/.sf/runtime.pidPID of the foreground / daemonized runtime.
~/.sf/runtime.logAppend-only log of tick activity, fills, and errors.
~/.sf/runtime-executed.jsonDe-dupes execution attempts across crashes.

CLI

sf runtime start

sf runtime start                     # foreground
sf runtime start --daemon            # background; logs to ~/.sf/runtime.log
sf runtime start --smart             # enable LLM soft-condition evaluation
sf runtime start --smart --daemon
FlagDefaultNotes
--daemonoffDetach into a background process. PID written to ~/.sf/runtime.pid.
--smartoffEvaluate softCondition strings on intents (“only if VIX < 20”) with the configured LLM. Costs LLM tokens.
Refuses to start if Kalshi credentials aren’t configured; the fix is sf setup --enable-trading.

sf runtime stop

sf runtime stop
Sends SIGTERM to the PID in ~/.sf/runtime.pid. Falls back to scanning for orphan runtime processes.

sf runtime status

sf runtime status
sf runtime status --json
Returns daemon liveness, last tick timestamp, count of intents per status, and a recent error trail.

Intents

An intent is a persisted instruction to do something on a venue when a trigger fires. Create them with the CLI or the HTTP API.

Create an intent (CLI)

sf intent buy <ticker> <quantity>  [flags]
sf intent sell <ticker> <quantity> [flags]
FlagDefaultNotes
--price <cents>none (market)Max price per contract in cents (1–99).
--side <yes|no>yesDirection.
--trigger <trigger>immediateSee trigger forms below.
--soft "<condition>"noneNL condition the runtime evaluates each tick when --smart is on.
--expire <duration>1dWhen the intent auto-cancels: 1h, 6h, 1d, 3d, 1w.
--venue <kalshi|polymarket>kalshiVenue.
--rationale "<text>"noneFree-form why-string saved on the intent.
--autooffSkip the interactive confirmation.
--style <immediate|twap>immediateExecution style. twap slices the order over time.
--jsonoffReturn JSON envelope.
Trigger forms
FormMeaning
immediateFire on the next tick (or right now if not arming).
below:<cents>Fire when price ≤ that many cents.
above:<cents>Fire when price ≥ that many cents.
time:<ISO>Fire at the given ISO-8601 timestamp.
Soft conditions (--soft) are evaluated by the configured LLM on every tick when --smart is enabled. Examples:
--soft "only if Polymarket twin is at least 4c richer"
--soft "skip if SimpleFunctions Index moved more than 3 points in the last hour"

List + cancel

sf intent list                   # active only
sf intent list --all --json      # all statuses, JSON
sf intent list --status armed
sf intent cancel <id>

Lifecycle

created → armed → triggered → executing → filled

                                  └→ canceled | expired | failed
StatusMeaning
createdPersisted but not yet activated (e.g. waiting for activateAt).
armedWatching; trigger has not fired.
triggeredTrigger fired this tick; runtime is about to submit.
executingOrder submitted, awaiting fill.
filledFully filled (or partially, if the venue closed early).
canceledUser canceled.
expiredexpireAt passed without firing.
failedVenue rejected or runtime errored. The error is captured on the intent row.

Intents API

POST   /api/intents
GET    /api/intents
GET    /api/intents/{id}
PATCH  /api/intents/{id}
DELETE /api/intents/{id}
Auth: required.

POST /api/intents

Required body fields
FieldTypeNotes
action"buy" | "sell"Order direction.
venue"kalshi" | "polymarket"Venue.
marketIdstringKalshi ticker or Polymarket conditionId.
marketTitlestringDisplay title — saved on the intent for UX.
direction"yes" | "no"Contract side.
targetQuantityinteger ≥ 1Number of contracts to fill.
Optional body fields
FieldTypeNotes
maxPriceinteger 1–99Max price per contract in cents.
executionStyle"immediate" | "twap"TWAP slices the order.
triggerTypestring"immediate", "price_below", "price_above", "time".
triggerPricenumberCents threshold for price triggers.
triggerAtISO timestampFor triggerType: "time".
triggerParamsobjectTrigger-specific extras.
softConditionstringNL condition evaluated each tick when --smart is on.
expireAtISO timestampWhen the intent auto-cancels.
autoExecutebooleanIf true, skip confirmation.
sourcestringFree-form attribution ("cli", "agent", …).
sourceIdstringLinked thesis id, evaluation id, etc.
rationalestringWhy-string saved on the intent.
Errors
StatusBodyCause
400Missing required fields: ...Missing required field.
400action must be "buy" or "sell"Bad enum.
400venue must be "kalshi" or "polymarket"Bad enum.
400direction must be "yes" or "no"Bad enum.
400targetQuantity must be a positive integerBad number.
400maxPrice must be 1-99 centsOut of range.
401unauthorizedNo / invalid auth.

GET /api/intents

QueryNotes
statusFilter (active, armed, triggered, executing, filled, canceled, expired, failed).
venueFilter by venue.
sourceFilter by source field.
limitCap on rows.

PATCH / DELETE

PATCH updates status, softCondition, expireAt, or triggerParams. DELETE cancels.

Smart mode

--smart enables three behaviors:
  1. Soft-condition evaluation. Each tick, if any active intent has a softCondition, the runtime calls the LLM with current market context and the condition. Only fires the order if the LLM returns a clear positive.
  2. Edge re-check before firing. Just before submitting the order, the runtime calls inspect_ticker on the market and aborts if the suggestion has flipped to avoid.
  3. Adaptive delay. Trades that look like they’d cross the spread are deferred until the spread is reasonable — implementation default is 8 cents.
Smart mode costs LLM tokens; budget with sf agent --budget-usd ... and / or per-thesis monthlyBudgetUsd on heartbeat.

Risk gates

The runtime calls the same risk-gate engine as the autopilot tick. Before any order is placed it checks:
  • per-trade max notional
  • per-market exposure cap
  • daily loss circuit breaker
  • max open positions
  • minimum balance
  • per-tick max orders
A rejected order writes a structured risk_gate_fail reason to the intent and stops there — the intent stays armed for the next tick. See Risk gates.

Cloud runtime (BYOK)

The cloud runner gives you “always on” without keeping a laptop awake. Treat this as an advanced operator surface: start locally, verify dry-run behavior, then connect cloud credentials only when you are ready for unattended automation.

Enable

sf setup --cloud                     # encrypt & upload exchange keys
sf runtime start --remote            # boot cloud container (~3s cold start)
sf runtime stop --remote             # scale to zero
sf --remote agent ...                # route any agent command through the cloud
sf setup --cloud connects encrypted exchange credentials for the cloud runner. The API never returns plaintext credentials; rotate or revoke them from the CLI when access should change. The cloud runner uses the same intent + tick + risk-gate code paths as the local runtime. The only difference is the host.

One-shot remote exec

POST /api/runtime/exec
GET  /api/runtime/exec?runId=...
Used by sf --remote <command>. Sends a single CLI invocation to the cloud runner, returns a runId, and lets you stream or poll output. Auth: Authorization: Bearer sf_live_.... This is not a long-running daemon — for that, use sf runtime start --remote.

Events

Runtime emits webhook events when configured:
EventWhen
intent.armedTrigger watcher attached.
intent.triggeredTrigger fired.
intent.executingOrder submitted.
intent.filledOrder fully filled.
intent.canceledUser canceled.
intent.expiredexpireAt passed without firing.
intent.failedVenue rejected or runtime errored.
Configure receivers via Webhooks.

Operational tips

  • Run sf doctor before going live to catch missing keys, time-skew, or a stale CLI.
  • Use sf intent list --all --json to review what the runtime is watching before you start it in --smart mode (smart-mode runs LLM calls).
  • Soft conditions are tokens; over-broad conditions on many intents accumulate cost. Prefer hard triggers when the rule is mechanical.
  • Cloud runner respects executionModedry-run evaluates everything but skips placing orders. Flip to live only when you’re satisfied with dry-run output.
sf agent --plain                     # interactive agent (uses intents under the hood)
sf agent --headless --deny trade,runtime
sf telegram --daemon                 # mobile operator visibility
sf agent is for reasoning + tool use. sf telegram is for human-in-the-loop. The runtime is the worker that closes the loop.

See also

Trade intents

The intent-object model in depth.

Risk gates

Pre-trade safety rails.

Portfolio autopilot

Cloud-run portfolio loop with BYOK credential connection.

Webhooks

Signed delivery for runtime events.