Skip to main content
A variable comes into being when an equation first references it by name — see Writing activities. Defining a variable is configuring everything else about it: the labels it reads under, how its value is displayed, and the default it takes when none is provided.

What you configure

  • Key — the identifier used in equations and in input.
  • Title and description — human- and agent-readable labels.
  • LLM prompt — optional, authoring-only instructions for interpreting natural-language input onto this variable, kept separate from the description.
  • Display type and format — how the value is interpreted and shown.
  • Default value — an optional value, with its unit, used when none is provided.

Key and labels

A variable’s key is its identifier within the domain. It is the name you write in equations and the name you reference when you set or solve for the variable in structured-text input. A key starts with a letter and contains letters, digits, and underscores, and is unique within the domain: home_price, interest_rate, loan_term. It’s always lowercase. To rename a variable, edit its key here, in the variable’s details. The change propagates to every equation that references it, so the variable stays a single thing under its new name. Renaming inside an equation does not work this way: because a variable comes into being the moment an equation references a key, typing a name there that no longer matches an existing key creates a new variable instead of renaming the old one. Rename from the variable’s details, not by editing equation text. The title and description are labels. They do not affect calculation, but clear, specific titles and descriptions improve natural-language and agent results, so keep them clear and specific.
Describe variables in the words users say. Clear, inclusive titles and descriptions improve natural-language and agent results, so phrase them the way a user would — and include the variations they might use. A home-price variable’s description might mention “home price, property value, purchase price.” When natural-language requests keep landing on the wrong variable or none at all, the fix is almost always a clearer or more inclusive description, not a change to the equation. And when two variables could be described the same way, note in each how it differs from the other — “the rate after points, not the note rate” — so results land on the one you mean.
State the unit and form a value should take. Where the form of a value isn’t obvious, say so in the description — a term as a length of time such as 30 yr or 360 mo. This keeps input both correct and consistent. Watch for a variable whose value arrives in a different form from one run to the next — the same term coming back as a bare 360 on one request and 30 yr on another — which usually traces to a loose description. The fix is to tighten the description so it names the unit the value should carry, not to change the equation.

LLM prompt

A variable can carry an optional prompt — guidance for interpreting natural-language input onto this variable. The prompt is distinct from the description, and the two serve different purposes:
  • The description is the customer-facing label. It is what the API, conversation sharing, and the MCP tools return for the variable.
  • The prompt is authoring-only. It is never returned by the API, a calculation result, conversation sharing, or the MCP tools. Use it for interpretation guidance you want to apply to natural-language input but do not want to surface to callers.
The prompt is optional. Left empty, the description alone guides interpretation. When you set it, it supplements the description rather than replacing it, so keep the description clear regardless of what the prompt says. Set the prompt in the Builder, in the LLM Prompt field below Description. It travels with the domain through export, import, and copy, so it round-trips for authors, while staying absent from every public response.

Display type

A variable’s display type sets how its value is interpreted and presented:
  • number — a plain number, shown with thousands separators and the unit its value carries, if any. A monetary amount is a number whose unit is a currency.
  • percent — a rate shown as a percentage. A unit on the value is still shown — 0.20 ft displays as 20% ft — though pairing a unit with a percentage is unusual.
  • no_separator — a number shown without thousands separators, such as a year, with the unit its value carries, if any.
  • table — a collection of values in named rows and columns. See Tables.
  • bar_chart / pie_chart — a table presented as a chart. See Charts.
For the scalar types — number, percent, and no_separator — you also set a decimal format, the precision applied when the value is shown: Decimals 0 through 9 (decimals_0 through decimals_9) for a fixed number of decimal places, or float (decimals_float) to show the value’s natural precision, up to a maximum of 10 decimal places. The decimal format affects display only — the stored value keeps full precision and is what later steps compute with.

Default value and unit

A variable can carry a default value — the value used when a calculation provides none. A value supplied from a default is recorded with default provenance. A default is written as a value together with its unit, the way you would write it by hand — 0 USD, 30 yr, 0.065. The unit is part of the value, not part of the display type: the display type controls formatting, while the unit travels with the value through every calculation (see Units and precision). This is why a currency amount is simply a number whose value carries a currency unit — there is no separate “money” type. A variable with no default has none applied; if a calculation needs its value and none is provided, the value is left unset rather than assumed.
Default to what a typical user would assume Set a default to the value most callers would expect for the domain: a US mortgage might default its term to 30 yr, its down payment to 0.20, and a balloon payment to 0. The right default is the conventional answer, and it differs from one variable to the next. Leave a variable undefaulted when there is no safe assumption and the user should state it — a loan amount or a home price. A wrong default there is worse than none, since a missing value is left unset rather than invented.

Let variables carry their units

A dimensional quantity — a term, a distance, a price, a weight — should be a variable that carries its unit, not a bare number that assumes one. Model a loan term as a value entered in a unit of time (30 yr or 360 mo, either works), not as a loan_term_months whose name and description ask every caller to supply a unitless count of months. Carrying the unit is what makes the value safe: TrueMath validates it against the dimension it expects, converts it without loss wherever it is used, and keeps the whole calculation in units (see Units and precision). The description guidance above — state the form a value should take — still applies, but a carried unit enforces that form where a description only suggests it. Often you need no conversion at all: many functions accept unit-carrying values directly. Passing loan_term straight to a finance function works — the function reads the time value and converts it as needed — so there is no reason to hand it a bare month count. When a calculation does genuinely need a bare number — a count to drive a loop, say — strip the unit with a single explicit conversion within that one equation, not as a separate unitless variable carried through the domain: a loop bound can be written unitvalue(loan_term; "mo") at the point of use, while loan_term stays a time value everywhere else. Stripping a unit is strategic and local; the value that travels between activities should keep its unit. Reaching for unitvalue and unit throughout a domain is usually a sign a value was declared without the unit it should carry.
Don’t declare a unitless variable for a dimensional quantity. A bare 360 and a 30 yr describe the same term, but a variable typed to hold the bare count assumes its unit by convention — and that convention is invisible to the engine and to whoever supplies the value. Nothing catches a 30 that meant 30 years arriving where the domain expected 30 months, and the inconsistency stays silent until a downstream calculation produces a wrong result. Prefer a unit-carrying input and convert once where a bare number is actually required.
The display configuration you set here is what GET /v1/domains/:id/variables and GET /v1/domains/:id/activities return for each variable, and the same information a calculation result is rendered from. See Domains.