A few lines you write to say how your columns relate to what you want to predict. The core reads them, labels every generated row with them, and hands you back the rule it used and a fingerprint of the data.
Every screenshot on this page comes from a real session, driven from the first screen to the last. Nothing here is a mock-up.
The model was built from one sentence with its ranges declared in it, so the numbers you see can be checked: debt_euros runs from 0 to 500,000 euros and age_years from 18 to 95. And the recipe was not typed — it is the example the product writes for you with your own columns, put in the box with one click. That is why its thresholds are 350,000 and 41.
The box sits in phase 2, Data, under GENERATE DATA WITH THE CORE — above the button, so that what it says about generating without one is read before you press, not after you train. The Workbench has the same box in the Data view of the model: same language, same texts, same core. A short version of this manual travels inside the product too, folded under How to write a recipe right next to the box.
Generated rows used to get their answer from a coin toss, and that is measured, not felt. Over 400 rows, any correlation below 0.098 is indistinguishable from chance. The highest correlation between any input column and the target was 0.049 for a binary target and 0.054 for a continuous one. There was nothing in there to learn.
The consequence landed on whoever had just installed the Studio: generate data, train, and read about 50 % accuracy. The product reported that honestly — and anyone looking concluded the product did not work.
With a recipe, the same walk-through — one sentence, 200 generated rows, a rule with 8 % declared noise — trained to 87.5 % accuracy. Measured end to end on 2026-08-18, driving the application.
A recipe for a target with classes is a list of rule lines and one DEFAULT. This is the one the third screenshot on this page was generated with:
# the first matching line wins
1: debt_euros > 350000 AND age_years > 41
DEFAULT: 0
NOISE: 0.08
BALANCE: 1=0.3, 0=0.7label: condition. The label is either a name (HIGH, LOW) or a number (1, 0) — both are accepted, because a binary target's labels are not identifiers. It has to be one of the labels your model declares.DEFAULT: is what every other row gets. It is required — a recipe whose default is missing, or names a label the model does not have, is rejected.DEFAULT. One outcome for everything is not a rule, it is a constant, and it is rejected as such.# are comments.A condition is exactly column OPERATOR number, and the operators are <, <=, >, >=, == and =. The last two mean the same thing and compare with a tolerance of 1e-9, so an equality on a decimal column behaves the way you would expect.
Four things it cannot do, and none of them raise an error:
AND and OR on the same line.The last one is the one that surprises people, so it is worth being blunt: a line with both combiners is discarded whole. The parser does not guess a precedence it was never told, and it does not complain either — the line simply is not there any more. Write two lines instead, and let the order do the work:
# not this — the whole line is dropped
1: debt_euros > 350000 AND age_years > 41 OR age_years < 25
# this — first match wins, so the order is the precedence
1: age_years < 25
1: debt_euros > 350000 AND age_years > 41
DEFAULT: 0Write debt_euros > 350000, not debt_euros > 0.7. Euros, years, degrees, millimetres — whatever that column is measured in. This is the mistake that breaks more recipes than every other rule on this page put together, and the product's own example used to make it.
The reason it is so easy to make is that the core samples rows in a normalized 0-to-1 space internally, and converts your threshold into it using the range of that column. What it deliberately does not do is clamp: a threshold outside the column's range stays outside, so the condition is correctly never true — instead of being quietly pulled to the edge and half-working.
So debt_euros > 0.6 on a column that runs from 0 to 500,000 is true for every single row. Every row gets the same label, the recipe is perfectly valid and completely useless, and the core notices: it falls back to random labels and says so.
NOISE: 0.1One row in ten does not follow the rule. It is a proportion between 0 and 1, not a spread, and it is written that way because it explains itself in one sentence and works the same for two classes or for five. RUIDO is accepted too; NOISE is the canonical spelling, like DEFAULT, AND and OR.
BALANCE: 1=0.3, 0=0.7Thirty per cent of the rows should be class 1. 1=30% works as well, and REPARTO is accepted as a synonym. Without it the split is whatever the rule and the ranges happen to produce.
That matters more than it sounds. In real life the default, the failure and the readmission are the minority, and being the minority is exactly what makes them hard to learn. A dataset where the rare class is not rare teaches a problem nobody has.
How the split is reached is part of the promise. Rows are not relabelled — that would break the rule, and the dataset would stop obeying its own recipe. The surplus rows are resampled, over and over, until the rule by itself produces the split you asked for. And if it cannot get there, that is declared rather than quietly missed.
A rule with labels is no use for a continuous target: there is no label to pick, there is an amount to compute. So the recipe becomes an expression.
usage = 0.05*sqm + 1.2*people + 5
NOISE: 0.1= is the target. Right of it is a sum of coefficient*column terms and a constant. A term written without a coefficient counts as 1, and the sign belongs to the term.NOISE means something different here, and it is worth saying out loud: a continuous target cannot be «contradicted», it drifts. NOISE: 0.1 shifts each value by up to 10 % of the range the target actually covers. Without it the fit comes out perfect, and an R² of 1.000 does not survive a second look either.Before this existed, a continuous target was filled with a uniform draw between its bounds — pure noise, correlation 0.054 — so a regression model had nothing to converge on.
Generating does not just hand you rows. Next to the data you get the rule the core actually applied, who wrote it, the fingerprint of the dataset, and any warning it raised.
BALANCE: 1=0.3, 0=0.7 comes back as one line per label, and NOISE is printed last. If a line of yours is missing from here, the parser dropped it — which is the fastest way to find a typo.The manual that lives inside the product sits one click from the box, and it writes its examples with your model's columns and ranges, so they can be used without translating anything:
data_ followed by the first 16 hexadecimal characters of the sha256 of the generated CSV. The same recipe with the same seed gives the same fingerprint and therefore exactly the same rows — the noise and the resampling draw from the same random stream as the columns, so the seed still rules.data_recipe) and comes back with it: close the Studio, reopen the project, and the dataset can be rebuilt.data_recipe.txt, next to the inference spec — so whoever receives a model can read what data trained it and under which rule.