How to write the questions of a decider
This guide shows how to build the decision: block of a decider step by step: which words are fixed, which ones you choose, which type to pick for each question, and how to read the answers. It assumes you already have a decider that runs — if not, start with How to ask a decision model.
What is fixed, what is yours
decision: # fixed
timeout: 60s # fixed (optional)
questions: # fixed
hurry: # YOURS: any name
type: noul # fixed word, one of: choice, noul, score
instructions: The message contains a word asking for speed, such as quick, fast, asap or now. # YOURS
level: # YOURS
type: choice
instructions: How familiar is the person with git? # YOURS
criteria: # fixed word
beginner: New to git # YOURS: the option (key) and what it means (text)
expert: Knows git well
hurry, upset, level, beginner… are names you choose, not keywords. mm and the model attach no meaning to them: the model reads only the instructions and the criteria texts. The name is the key you will find in the answer (answers.hurry), so pick one your script or your prompt can use.
The keywords are decision, timeout, questions, type, instructions, criteria, and the three type names.
Steps
1. Say what the decider reads
The decider reads one message, alone — the "state": a ticket, a command, the description of a game situation. No history, no system prompt. Everything it must know has to be in that message.
2. Split the decision into questions
One question per thing you want to know. "How serious is this ticket?" may become three: how soon (a level), is there a danger sign (yes or no), who should handle it (one option). All the questions are answered together, in one pass, a fraction of a second.
3. Pick a type for each question
| You want… | Type | instructions is… |
criteria |
You get back |
|---|---|---|---|---|
| one option out of a list | choice |
a question | a mapping option: description, at least 2 |
choice (the option's key), probabilities (one per option), confidence |
| a yes or a no | noul |
a statement about the message | none | noul: the probability, from 0 to 1, that the statement is true |
| a level on a scale | score |
a question | a list of 2 to 10 levels, lowest first | score (from 0 to n−1, may fall between two levels), legend (number → level), probabilities, confidence |
noul is the yes-or-no type. You do not ask a question, you write a statement — "The message describes chest pain" — and the decider gives the probability that it is true for this message: 0.96 means "almost certainly yes", 0.01 "almost certainly no". Your script decides where yes starts (0.5 is a common threshold, higher when a false yes is costly).
score returns a number, not a level: 2.81 on four levels means "between today and now, much closer to now". Round it to read the level in legend.
4. Write the instructions
choiceandscore: a question — "Which spell should I cast now?".noul: a statement — "My character is badly hurt." A yes-or-no question works too: on five git questions, "Is the person upset?" and "The person is worried, stressed or upset." gave the same verdicts (0.97 and 0.99 on the two upset messages, 0.14 at most on the three calm ones).- Name what is in the text, not an intention. Measured with LiquidAI d1-3B: "The person is in a hurry or asks for a short answer" scored 0.5 to 0.7 on calm questions too; "The message contains a word asking for speed, such as quick, fast, asap or now" gave 0.03 on a calm question and 0.98 on "quick: …". Likewise "signs of a stroke" scored 0.27 on a textbook stroke, "a sudden weakness of an arm or a leg, slurred speech" 0.96.
5. Write the criteria
choice: the key is what you get back (fireball), the text is what the model reads to choose — say when to pick that option:fireball: Many enemies close together, far enough from my friends.score: the levels, lowest first, as short phrases:[harmless, risky, deadly].noul: nothing.
The order of the file is kept: in the request, in the answer, and in the line display.
6. Try it
With spell.yaml from demos/decision-questions/ (the complete file is in the examples):
mm -config spell.yaml -p "An ogre is raising its club to hit me right now."
{"model":"hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M","answers":{"spell":{"type":"choice","choice":"shield","probabilities":{"fireball":0.024,"magic_missile":0.043,"shield":0.878,"misty_step":0.043,"sleep":0.011},"confidence":0.848}},"usage":{"input_tokens":109,"output_tokens":0}}
(numbers shortened here; the server gives them in full.) Without -p, mm -config spell.yaml shows one line per question for each message you type, then the same JSON.
7. Read the answers
The envelope is always the same — model, answers, usage — and answers has one entry per question, under the name you chose, with the fields of its type (step 3). What changes from one decider to another is only the names and the number of questions.
choice: readchoice; treat a lowconfidence(under 0.5 or so) as "unsure".noul: comparenoulwith your threshold.score: readlegend[round(score)], or comparescoreitself (> 2.5).
Examples
Each example is a complete agent file in demos/decision-questions/: copy it, or run it from that folder with mm -config <file> -p "<message>". All answers below were measured on 2026-10-24 with LiquidAI d1-3B Q4_K_M on llmman.
Symptom tickets: how serious is it?
symptoms.yaml:
# A decider: Symptom tickets: how serious is it?
# An example of the guide docs/{en,fr}/how-to/write-decision-questions.md.
#
# mm -config symptoms.yaml -p "My father suddenly cannot lift his right arm and his speech is slurred, it started 20 minutes ago."
#
# Pull the model once: llmman pull hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
provider: llmman
model: hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
baseUrl: http://127.0.0.1:17434/v1
fallback: http://host.docker.internal:17434/v1
decision:
questions:
severity:
type: score
instructions: How soon should this person see a doctor?
criteria: [it can wait for a usual appointment, within a few days, today, now - call the emergency number]
red_flag:
type: noul
instructions: The message describes a sudden weakness of an arm or a leg, slurred speech, chest pain, trouble breathing, heavy bleeding or fainting.
who:
type: choice
instructions: Who should see this person first?
criteria:
pharmacist: A minor problem a pharmacist can advise on
family_doctor: A usual problem for a general practitioner
specialist: A known long-term condition followed by a specialist
emergency: A problem that cannot wait
# A decider gets no tool: mm turns bash, the file tools, plan, ask_user and
# skills off by itself (no `…: false` lines needed).
agentsMd:
enabled: false
| Ticket | severity | red_flag | who |
|---|---|---|---|
| My father suddenly cannot lift his right arm and his speech is slurred, it started 20 minutes ago. | 2.81 → now (0.81) | 0.96 | emergency (0.86) |
| I have a tight pain in my chest and my left arm since an hour. | 2.60 → now (0.60) | 0.56 | emergency (0.83) |
| I have had a sore throat and a runny nose for two days, no fever. | 0.82 → within a few days (0.49) | 0.01 | pharmacist (0.30) |
Put the danger signs in a noul of their own and let it win over the score: the chest pain got only 0.56 on red_flag, so a threshold of 0.5 catches it and 0.8 would not. A decider sorts tickets; it does not make a diagnosis, and a person must read what it sends to "can wait".
421: which dice to throw again?
dice421.yaml:
# A decider: 421: how many dice to throw again? The script writes what is missing: a decider reads, it does not count.
# An example of the guide docs/{en,fr}/how-to/write-decision-questions.md.
#
# mm -config dice421.yaml -p "Dice: 4, 2, 6. In place for 421: 4 and 2. Missing: 1."
#
# Pull the model once: llmman pull hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
provider: llmman
model: hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
baseUrl: http://127.0.0.1:17434/v1
fallback: http://host.docker.internal:17434/v1
decision:
questions:
reroll:
type: choice
instructions: How many dice should the player throw again?
criteria:
none: Nothing is missing
one: One die is missing
two: Two dice are missing
all: All three are missing
# A decider gets no tool: mm turns bash, the file tools, plan, ask_user and
# skills off by itself (no `…: false` lines needed).
agentsMd:
enabled: false
| State sent | reroll |
|---|---|
Dice: 4, 2, 6. |
none (0.33) — wrong |
Dice: 4, 2, 6. In place for 421: 4 and 2. Missing: 1. |
one (0.80) |
Dice: 4, 5, 6. In place for 421: 4. Missing: 2 and 1. |
two (0.62) |
Dice: 3, 5, 6. In place for 421: nothing. Missing: 4, 2 and 1. |
all (0.76) |
Dice: 4, 2, 1. In place for 421: 4, 2 and 1. Missing: nothing. |
none (0.96) |
A decision model reads; it does not count. Given the dice alone it was wrong; once the script wrote what is missing into the state, it was right four times out of four. But then the script had already done the work: a rule like this one is better written in code. Keep the decider for what a rule cannot say — "is my opponent's score worth taking the risk?", described in words.
Dungeons & Dragons: which spell for my wizard?
spell.yaml:
# A decider: Dungeons & Dragons: which spell for my wizard?
# An example of the guide docs/{en,fr}/how-to/write-decision-questions.md.
#
# mm -config spell.yaml -p "An ogre is raising its club to hit me right now."
#
# Pull the model once: llmman pull hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
provider: llmman
model: hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
baseUrl: http://127.0.0.1:17434/v1
fallback: http://host.docker.internal:17434/v1
decision:
questions:
spell:
type: choice
instructions: I am the party's wizard. Which spell should I cast now?
criteria:
fireball: Many enemies close together, far enough from my friends
magic_missile: One weak enemy to finish off, or one that is hard to hit
shield: An enemy is about to hit me
misty_step: I am surrounded or grabbed and must get away
sleep: Several weak enemies, and we would rather not kill them
# A decider gets no tool: mm turns bash, the file tools, plan, ask_user and
# skills off by itself (no `…: false` lines needed).
agentsMd:
enabled: false
| Situation | spell |
|---|---|
| Five goblins are standing in a tight group 40 feet away. My friends are behind me. | fireball (0.50) |
| An ogre is raising its club to hit me right now. | shield (0.85) |
| Two wolves have grabbed me and the rest of the party is far away. | misty_step (0.47) |
| One goblin is left, almost dead, hiding behind a crate. | magic_missile (0.58) |
Each description says when to cast the spell, not what it does: the decider matches the situation against these conditions.
Dungeons & Dragons: fight or flee?
fight.yaml:
# A decider: Dungeons & Dragons: fight, flee or talk?
# An example of the guide docs/{en,fr}/how-to/write-decision-questions.md.
#
# mm -config fight.yaml -p "A troll guards the bridge. It says it will let us pass if we pay one gold coin."
#
# Pull the model once: llmman pull hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
provider: llmman
model: hf.co/LiquidAI/d1-3B-GGUF:Q4_K_M
baseUrl: http://127.0.0.1:17434/v1
fallback: http://host.docker.internal:17434/v1
decision:
questions:
action:
type: choice
instructions: What should my character do now?
criteria:
fight: We can win this fight
flee: We would probably lose, and there is a way out
talk: The enemy might listen, a fight is not needed
danger:
type: score
instructions: How dangerous is this situation for my character?
criteria: [harmless, risky, deadly]
hurt:
type: noul
instructions: My character is badly hurt.
# A decider gets no tool: mm turns bash, the file tools, plan, ask_user and
# skills off by itself (no `…: false` lines needed).
agentsMd:
enabled: false
| Situation | action | danger | hurt |
|---|---|---|---|
| We are four, full health, facing two tired bandits on an open road. | fight (0.17) | 1.15 → risky | 0.18 |
| I am alone with 3 hit points left, a red dragon lands in front of me, the cave exit is behind me. | flee (0.56) | 1.76 → deadly | 0.97 |
| A troll guards the bridge. It says it will let us pass if we pay one gold coin. | talk (0.64) | 0.64 → risky | 0.31 |
The bandits got fight with a confidence of 0.17: the right option, but barely ahead of talk. Asking danger and hurt as well lets your script decide when action is unsure — for example, flee when hurt is above 0.8, whatever action says.
Common mistakes
| Mistake | Effect | Fix |
|---|---|---|
| An intention or a diagnosis ("is in a hurry", "signs of a stroke") | middling probabilities on every message | name what can be read in the text |
choice descriptions that say what an option is |
the decider cannot match the situation | say when to pick it |
score levels highest first |
the score reads backwards | lowest first |
| Arithmetic or counting in the question | wrong answers | compute in the script, or put the result in the state |
| Context only in the history | the decider never sees it | put it in the message: the decider reads nothing else |
See also
- Configuration reference —
decision: every key and every field of the answers - How to ask a decision model: serve the model, write the agent file, ask it from a script, a hook or another agent
- Decision models — explanation: why a decider is an agent, what was measured
- Demos:
demos/decision-only/,demos/decision-reviews/,demos/decision-moderation/(a decider alone),demos/decision-chat/(a decider before a chat agent)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
|