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.
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.
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 anumberwhose unit is a currency.percent— a rate shown as a percentage. A unit on the value is still shown —0.20 ftdisplays as20% 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.
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.
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.
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.
