Browse documentation
Docs/Functionality

Build A Live Model

A live Grid model combines editable inputs, external data, formulas, and realtime updates.

Watch it in Grid

See the concept in Grid.

Use the film for the product interaction and this article for the complete contract and reference detail.

Build A Live Model

A live Grid model combines editable inputs, external data, formulas, and realtime updates.

Pattern

Input or external value changes
  -> dependent formulas update
  -> rules may fire
  -> workbook surfaces show the new state

Event Connectors

Event connectors normalize provider updates into source events. Examples include market data, weather, Firebase, ElectricSQL, and webhook-driven monitor events.

Treat connector-fed cells like any other input: keep their names stable, add type tags when the meaning matters, and use fallback formulas for data that may arrive late.

Connector-fed tables can remain ordinary relational Grid models too. Author the same SELECT, keyed join, calculation, filter, and grouping you would use for a snapshot:

table PaidOrders = SELECT customer_id, product_id, amount AS revenue
  FROM Orders
  WHERE status = "paid"

table LiveMargins = SELECT o.customer_id,
    o.revenue * (1 - COALESCE(p.cost_rate, 0)) AS margin,
    p.category
  FROM PaidOrders AS o
  LEFT JOIN Products AS p ON o.product_id = p.product_id
  WHERE o.revenue > 0
    AND (p.category IN ("software", "services") OR p.category IS NULL)

table MarginByCategory = SELECT category, SUM(margin) AS margin
  FROM LiveMargins
  GROUP BY category

Grid keeps the admitted relation current from source-row changes, including edits on either side of the join. The resulting tables still feed normal cells, rules, and rendered surfaces. Unsupported query shapes retain their authored Workbook evaluation path instead of silently changing meaning.

There is no second Live Model language and no operator-specific save command. An ordinary authored table Name = <relation> becomes live automatically when it is backed by changing sources and belongs to the documented fragment. Redeploying a changed definition performs a checked replacement. Removing the definition from source removes its compiler-owned target during reconciliation; an operator may also use dropLiveModel for an explicit owned-only drop.

The maintained set fragment includes UNION ALL, UNION DISTINCT, and binary INTERSECT/EXCEPT with or without ALL. Grid tracks their value multiplicities through the same Live Model plan; duplicate-count changes only publish when they change the visible multiset. Broad or unaddressable changes fall back to an exact atomic rebuild.

Inspect The Live Contract

Every admitted relational Live Model is visible through the model manifest at runtime.liveModels and directly at:

GET /api/models/<model-id>/live-models

The descriptor is a read-only projection of the same durable catalog and checkpoint used by execution. It reports:

  • the source schemas and ordered source revision vector;
  • a definition version and opaque plan digest (never provider SQL);
  • the committed target schema and revision;
  • the source high-water and last-applied checkpoint;
  • current, stale, or failed freshness;
  • the last physical refresh strategy and bounded failure text, if any.

Inspection never refreshes the model. stale therefore means a source has advanced past the committed checkpoint; failed retains that checkpoint and the last successful refresh while exposing the later failed attempt. Ordinary connector and table mutation paths normally settle back to current before publishing dependent cells and rendered surfaces.

Inspection is capped at 50,000 definitions/sources/observations. The direct endpoint fails closed above that bound; the manifest retains its other runtime metadata and reports runtime.liveModels.inspectionError.

Read And Explain

Every operational read chooses its freshness contract:

readLiveModel(modelId, {
  name: "MarginByCategory",
  policy: "requireCurrent",
  page: { offset: { offset: 0, limit: 100 } }
})

requireCurrent refreshes the dependency chain and either returns a current committed generation or fails. allowStale never initiates work; it returns the last committed generation together with its exact source high-water and freshness.

Use:

explainLiveModel(modelId, "MarginByCategory")

to see the admitted delta strategy, the strategy selected for the last refresh, the current/successful checkpoints, and any exact fallback reason. Fallback reasons distinguish schema change, broad change without row identity, delta-budget overflow, and unavailable incremental state. A broad fallback is an atomic fresh rebuild. A relational shape outside the supported fragment is not given a Live Plan at all and continues to use its authored Workbook semantics.

Dense Range Connectors

Dense range connectors update a rectangular block at once. Use them when an external source naturally sends a table or time-series frame instead of one event per symbol.

Downstream formulas can point at the range directly:

prices = A1:D50
latest_close = INDEX(prices, ROWS(prices), 4)

External Functions

Use external functions when the model should fetch or compute something on demand:

rate = FX_RATE("EUR", "USD") DEFAULT 1.08
quote = HTTP_JSON("https://api.example.com/quote") DEFAULT {}
score ~= ML_SCORE([margin, churn_risk, tenure]) DEFAULT 0

Use DEFAULT, IFERROR, or WITH ... ELSE so the rest of the model stays readable while the external value is pending or unavailable. See ../language/external-functions.md.

Reactive Rules

Use rules when the model should act on live state:

WHEN risk_score > 0.8 THEN
  status = "review"
  flagged_at = NOW()
END

For recurring checks, use EVERY; for one-shot moments, use AT. See ../language/rules-and-schedules.md.