> ## Documentation Index
> Fetch the complete documentation index at: https://docs.truemath.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Defining variables

> Configure a variable's key, labels, display type, decimal format, and default value with its unit.

A [variable](/concepts/variables) comes into being when an [equation](/authoring/writing-equations) first references it by name — see [Writing activities](/authoring/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](/authoring/writing-equations) and the name you reference when you set or solve for the variable in [structured-text input](/concepts/input-formats#structured-text). 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](/authoring/writing-equations) 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.

<Tip>
  **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.
</Tip>

<Tip>
  **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.
</Tip>

## 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](/api/domains), 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](/authoring/creating-a-domain#managing-a-domain), 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](/authoring/tables).
* **`bar_chart`** / **`pie_chart`** — a table presented as a chart. See [Charts](/authoring/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](/concepts/units-and-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](/concepts/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](/concepts/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.

<Tip>
  **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.
</Tip>

## 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](/concepts/units-and-precision#model-quantities-as-unit-carrying-values)). The [description guidance above](#key-and-labels) — 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](/math/functions/finance) 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`](/math/functions/units#unit-value) and [`unit`](/math/functions/units) throughout a domain is usually a sign a value was declared without the unit it should carry.

<Warning>
  **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.
</Warning>

<Note>
  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](/api/domains).
</Note>
