# Tutorial

From one question and its exit code to a saved question and a stream of messages.

## 1. Install it

*The download script*

```
curl -fsSL https://thinkthen.dev/install.sh | sh
```

*Homebrew, an option on a Mac*

```
brew install botassembly/thinkthen/thinkthen
```

The [install page](/install/) covers the key and every language and database.

## 2. Ask one question

Name the question, pipe the message in, and pass the question as an argument. `decide` prints a bare `true`, `false`, or `null`, and it sets the exit code to match.

*The ticket asks for a refund. decide prints true and exits 0.*

```
question="Does the customer ask for a refund?"

cat <<'EOF' |
I renewed once this morning, but my card shows two charges.
Please refund the duplicate.
EOF
thinkthen decide "$question"
```

*Output*

```
true
```

*exit 0: yes*

The exit code is the answer. A script branches on it the way it branches on `test`.

## 3. Set a band

`--threshold` is your bar on the probability. One number is a cut, and the default is 0.5. Two numbers make a band: under the low bar is no, at or over the high bar is yes, and anything between is not sure.

*"I want to send this back." could mean an exchange or money back. It lands inside the band 0.2:0.8. decide prints null and exits 3.*

```
question="Does the customer ask for a refund?"

printf '%s\n' "I want to send this back." |
thinkthen decide "$question" \
  --threshold 0.2:0.8
```

*Output*

```
null
```

*exit 3: not sure*

The threshold never changes the probability. It changes what you call a yes.

## 4. Branch on the answer

A script reads the exit code and hands a person the calls it should not make alone.

*The send-back line lands in the band. decide exits 3, and the case sends it to a person. The script then exits 0.*

```
question="Does the customer ask for a refund?"

printf '%s\n' "I want to send this back." |
thinkthen decide "$question" \
  --quiet \
  --threshold 0.2:0.8
refund_code=$?

case $refund_code in
  0) echo "refund it" ;;
  1) echo "answer it as usual" ;;
  3) echo "send it to a person" ;;
esac

test "$refund_code" -eq 3
```

*Output*

```
send it to a person
```

*exit 0*

## 5. Save the question to a file

A question file holds one question: the words, what a yes and a no mean, and the threshold.

*refund.json, the saved question*

```
{
  "decide": "Does the customer ask for a refund?",
  "true": "The customer asks for money back.",
  "false": "Anything else, such as a cancellation or thanks.",
  "threshold": "0.2:0.8"
}
```

Write `@refund.json` in place of the question words.

*The saved question answers true for a plain request for money back.*

```
cat <<'EOF' |
I would like to return this and get my money back.
EOF
thinkthen decide @refund.json
```

*Output*

```
true
```

*exit 0: yes*

*Sending it back could mean an exchange or money back. The band in the file calls it not sure. decide prints null and exits 3.*

```
printf '%s\n' "I want to send this back." |
thinkthen decide @refund.json
```

*Output*

```
null
```

*exit 3: not sure*

## 6. Judge a stream

`--lines` tells `decide` to judge each line as its own message. Each answer then prints as one JSON line with its input beside it. The input shows which answer belongs to which message. `jq .` spreads each line out to read.

*Each answer sits beside its message. The send-back line is the null from step 3.*

```
question="Does the customer ask for a refund?"

cat <<'EOF' |
Please refund my order. It arrived broken.
Thanks for the quick help yesterday!
I want to send this back.
EOF
thinkthen decide "$question" \
  --batch 1 \
  --lines \
  --threshold 0.2:0.8 |
jq .
```

*Output*

```
{
  "input": "Please refund my order. It arrived broken.",
  "value": true
}
{
  "input": "Thanks for the quick help yesterday!",
  "value": false
}
{
  "input": "I want to send this back.",
  "value": null
}
```

*exit 0*

`filter` reads one record per line with no flag. It keeps the records where the answer is yes, byte for byte and in order.

*filter keeps the two complaints: the broken zipper and the snapped strap.*

```
question="Is this a complaint?"

cat <<'EOF' |
Arrived a day early. Thank you!
The zipper broke the first time I used it.
Does this come in blue?
The strap snapped on day two.
EOF
thinkthen filter "$question" --batch 1
```

*Output*

```
The zipper broke the first time I used it.
The strap snapped on day two.
```

*exit 0: the run finished*

`rank` sorts the records by how likely the answer is yes.

*The outage comes first and the quote due today second. The bill due in a month comes third, and the newsletter that needs no reply comes last.*

```
question="Is this urgent?"

cat <<'EOF' |
Newsletter: our autumn catalog is here. No reply needed.
Our checkout page is down and customers cannot pay
Reminder: your invoice is due in 30 days
Please send the signed quote by 5 pm today
EOF
thinkthen rank "$question" --batch 1
```

*Output*

```
Our checkout page is down and customers cannot pay
Please send the signed quote by 5 pm today
Reminder: your invoice is due in 30 days
Newsletter: our autumn catalog is here. No reply needed.
```

*exit 0: the run finished*

Put them in a pipe and the second question reads only what the first kept. [See the leads how-to](/how-tos/rank-the-inbound-leads/) for `filter`, `rank`, and `choose` in one pipeline.

## 7. Ask many questions at once

`annotate` answers a question set for every record. A question set is any mix of `decide`, `choose`, `score`, and `tag` questions in one file.

*inbox-form.json, the question set*

```
{
  "version": 1,
  "questions": {
    "kind": {
      "choose": "What kind of message is this?",
      "options": [
        "billing",
        "delivery",
        "question"
      ]
    },
    "urgency": {
      "score": "How urgent is this?",
      "levels": [
        "Routine.",
        "Soon.",
        "Immediate."
      ]
    }
  }
}
```

*Three messages need a reply, each beside its kind and its urgency from 0 to 2. The order needed tonight sits near 2, Immediate. The thank-you note drops out.*

```
question="Does this need a reply?"

cat <<'EOF' |
Please fix the wrong amount on my invoice.
Just saying thanks, no reply needed.
Order never arrived and the party is tonight.
Do you ship to Canada?
EOF
thinkthen filter "$question" --batch 1 |
thinkthen annotate inbox-form.json \
  --batch 1 --lines |
jq .
```

*Output*

```
{
  "input": "Please fix the wrong amount on my invoice.",
  "value": {
    "kind": "billing",
    "urgency": 0.58
  }
}
{
  "input": "Order never arrived and the party is tonight.",
  "value": {
    "kind": "delivery",
    "urgency": 1.96
  }
}
{
  "input": "Do you ship to Canada?",
  "value": {
    "kind": "question",
    "urgency": 0.01
  }
}
```

*exit 0*

`filter` drops the thank-you note. Each message left comes back with one field per question.

ThinkThen answers. Your code acts.

[Next: Beatles Bench](/learn/beatles-bench/) · [Learn the Bash techniques](/how-tos/bash/)

On GitHub: [github.com/botassembly/thinkthen](https://github.com/botassembly/thinkthen)
