- Natural language — prose describing what you want.
- Structured text — explicit
key: valuelines. - JSON — a structured object carrying the same values as structured text. Available over the API only.
Natural language
Natural language is free-form prose. TrueMath uses a language model to parse your intent into the variables to set and the variable to solve for, then executes the calculation deterministically. Use it for exploration, or when you do not know a domain’s exact keys.Structured text
Structured text is one instruction per line, inkey: value form. It is precise and fast: there is no language to interpret, so the same input always produces the same request. Use it when you know the variables you want to set and the target you want to solve for.
Lines
Each line is one instruction:<key>: <value>— set a variable.<key>is the variable’s key.calculate: <key> [<unit>]— name the variable to solve for, optionally with the unit you want the result in (calculate: monthly_payment USD).scenario: <selector>— choose the scenario to calculate against (see Scenarios).# ...— a comment; the whole line is ignored.
calculate: and scenario: are optional. When omitted, they are inferred from the prior request in the conversation.
Values
Write a value the way you would by hand; the unit is part of the value (see Units and precision).- Numbers —
3000.54or3,000.54; thousands separators are optional. - Units inline —
30 yr,5.2 m,1500 USD; abbreviations or full names both work (yroryears,mormeters). See Units. - Currency — a leading
$is shorthand for USD:$1,000.00is the same as1000.00 USD. - Percent — a trailing
%is converted to a rate:6.5%becomes0.065. - Dates, times, and durations —
7/21/2026,2:30 PM,90 min,today. See Dates, times, and durations.
Dates, times, and durations
A variable typed as aduration, date, datetime, or time takes its value the way people write one, and TrueMath converts it to the count of seconds the variable stores. You never type seconds yourself. See Authoring dates and durations for what each kind holds.
Month and weekday names are English. A named weekday is checked against the date rather than taken on trust, so
Monday, July 21, 2026 is an error: that day is a Tuesday.
Numeric dates are read month-first, matching how they render: 10/5/2026 is October 5th and 5/10/2026 is May 10th. A two-digit year reads 00–49 as this century and 50–99 as the last, so 1/1/49 is 2049 and 1/1/50 is 1950. Write the year in full for a value near that boundary — a birth date especially.
A date with the year left out takes the current year, read in the same time zone as today (see Time zones). Feb 29 is a date in 2028 and an error in 2026.
A value that names its own time unit is read as written. 90 min, 1.5 hr, and the compound 1 hr 30 min are quantities of time already, and are taken as they stand.
These spellings work in natural language too. A date written the way you would say it — “what is the payoff if I close on July 21st?” — is read the same way as one typed into a field.
today and now
today and now name a moment rather than describing one. Either can be given as a value, and the moment used is the one the calculation runs at, in the caller’s own time zone:
date or datetime takes either, a time takes now, and a duration takes neither. For what each kind keeps, see today and now as defaults — the same rules apply to a value you supply and to a default an author sets.
Nothing else is read this way. tomorrow and next Friday are not keywords.
One genuine ambiguity: the colon
22:47 is either 22 minutes 47 seconds or 22 hours 47 minutes, and the text alone does not distinguish them. The variable’s kind and format are what separate the two readings, so the same string lands on a different number:
9:59 on a time or datetime is 9:59 AM whatever its format. For a duration, a third group states the reading outright — 0:22:47 is 22 minutes 47 seconds under any format — and a meridiem removes the ambiguity entirely.
Because only the variable separates the two readings, a colon value given to an ordinary number variable is an error rather than a guess.
A value written as a date is read as one or refused
A value written as a date — three numeric groups on one separator, or a month name — is either read as a date or returned asinput.invalid_prompt. This applies on any variable, not only one typed as a date or a duration, so a domain that predates those display types and holds its dates as plain numbers is covered too.
A table cell follows its column
Every rule above applies one level down inside a table. A table variable’s own display type is alwaystable, so the kind and the format come from the cell’s column:
- A refused cell is named by its column —
'Date' cell '2/45/26' is not a valid date— because there is otherwise no way to identify which of forty values is wrong. - A flat table is one column of many rows, so every cell in it is read against the first column. Rows need their own brackets.
Tables
A table value uses semicolons to separate cells — never commas, which collide with decimal and thousands separators. A one-dimensional table is a list on a single line; brackets are optional:[$3; $4] is two currency amounts, and [5%; 10%] becomes [0.05; 0.1].
A two-dimensional table is written as bracketed rows. Put the rows on one line, or one row per line:
Scenarios
scenario: selects which scenario the calculation runs against:
scenario: new— start a new scenario.scenario: last— the most recent scenario.scenario: first— the first scenario in the conversation.scenario: <index>— a specific scenario by its index.
scenario: is omitted, the calculation continues the conversation’s current scenario.
Persistence
Values persist within a conversation. A variable you set but do not use in the current calculation is retained and stays available until a later calculation needs it. Likewise, when you omitcalculate:, the prior target is retained. You can build up inputs across several requests and solve for different targets without restating values.
JSON
JSON expresses the same request as structured text, but as a structured object rather thankey: value lines. It is available over the API only — set input_format to json and pass the object as a JSON string in prompt. Like structured text, it is precise and deterministic: there is no language to interpret, so the same input always produces the same request, and the calculation runs synchronously.
The object has three fields:
inputs— an array of{ "key", "value" }objects, one per variable to set.keyis the variable’s key.calculate—{ "key", "unit" }naming the variable to solve for, with the optional unit you want the result in (nullfor the variable’s own unit). Setcalculatetonullto infer the target from the prior request in the conversation.scenario— the scenario selector as a string:"new","first","last", or an index such as"2". Set it tonullto continue the conversation’s current scenario.
Values in JSON
Eachvalue is a string, following the same conventions as a structured-text value — the unit is included in the string:
- Scalars and units —
"3000.54","30 yr","1500 USD". A leading$is shorthand for USD ("$1,000.00"), and a trailing%becomes a rate ("6.5%"→0.065). - A 1-D table — an array of cell strings:
["1500 USD", "1600 USD", "1700 USD"]. - A 2-D table — an array of row arrays:
[["1500", "12"], ["1600", "12"]].
Nothing recognized
A request that resolves to no inputs and no calculation target —{ "inputs": [], "calculate": null, "scenario": null } — is treated as “nothing recognized” and returns the input.llm_no_parsed_data error. This is the same signal used across every input format.
Round-trip
A completed calculation always returns its full result in theresults object. A structured-text request additionally gets that result serialized back as a structured_text string, so you can capture it, change a value, and resubmit. See Calculate for the response fields each input format returns.
