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

# Plan the next question

> Walk a person through the fewest questions that price a risk, one card at a time, for one rater or several.

[Install Relativities](https://docs.canary.effectiveai.app/relativities/setup.md) before running the synthetic examples.

`rslc plan` keeps one person's answers in a journey file and prints the next question as a card.
The planner asks only for inputs that still change a result.
[Rate with missing answers](https://docs.canary.effectiveai.app/rsl/how-to/rate-with-missing-answers.md) shows the result that each rater gives.

## Start a journey

Save the shared renters example, a rater from the synthetic carrier Example Mutual:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc examples get renters
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
WROTE renters/rater.rsl
WROTE renters/tables/BaseRate.csv
WROTE renters/tables/BuildingFactor.csv
WROTE renters/tables/DeductibleFactor.csv
```

Start a journey for the rater:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan start journey.json --rater renters=renters
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.insured_now: Do you have a renters policy now?
  section: Insurance
ready: none
```

* `journey.json` is the journey file. Each later command reads it and writes it back.
* `--rater renters=renters` gives the rater an ID and names the folder that holds `rater.rsl`.
* The first line of a card holds its kind, the path of the input, and the question.
* `ready` lists each rater that is settled.

## Answer a card

Pass the path of the card and the answer as JSON:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer journey.json Policy.insured_now false
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
number Policy.contents: What are your belongings worth?
  section: Home
  help: Count furniture, clothing and electronics.
  min: 10000
  max: 100000
ready: none
```

A `number` card shows the smallest and the largest answer.
The `help` line comes from the rater's `help` annotation.

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer journey.json Policy.contents 30000
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
choice Policy.territory: Where is the home?
  section: Home
  - "metro": Metro
  - "suburban": Suburban
  - "rural": Rural
ready: none
```

A `choice` card lists each answer as its JSON value, then its label.
A text answer keeps its JSON quotes, so wrap it in single quotes for the shell:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer journey.json Policy.territory '"rural"'
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.has_dog: Do you have a dog?
  section: Household
ready: none
```

The planner leaves `construction` out. Each rural row of the building table holds the same factor.

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer journey.json Policy.has_dog true
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.dog_has_bitten: Has the dog bitten anyone?
  section: Household
ready: none
```

`dog_has_bitten` is a follow-up input. The planner asks it only after `has_dog` is `true`.

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer journey.json Policy.dog_has_bitten false
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
done: every rater is settled
ready: renters
```

Five answers settle the rater. It declares seven inputs.

## Read the premium

The journey file holds the answers under `facts`. Rate them with `rslc.journey.Journey`:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
import json
from pathlib import Path

import rslc
from rslc.journey import Journey

state = json.loads(Path("journey.json").read_text())
journey = Journey({name: rslc.PreparedRater(folder) for name, folder in state["raters"].items()})
print(state["facts"])
# {'Policy': {'insured_now': False, 'contents': 30000, 'territory': 'rural', 'has_dog': True, 'dog_has_bitten': False}}
print(journey.evaluations(state["facts"]))
# {'renters': {'settled': {'ok': True, 'outputs': {'Policy': {'premium': 241}}}}}
```

The annual premium is \$241. [Results](https://docs.canary.effectiveai.app/rsl/reference/results.md) lists each field of an evaluation.

## Plan for several raters

A journey takes one `--rater` for each rater. Save a second, smaller rater as `basic/rater.rsl`:

> [accordion] Complete example: basic/rater.rsl
>
> ```rsl basic/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Renters Basic",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p2] = 6,
>     dog_surcharge [cite: manual:p3] = 40
> }
>
> Records = {
>     Policy = {
>         inputs {
>             contents: Num {precision: int} [ask: "What are your belongings worth?", group: "Home"]
>                 where self in [10000, 50000] [code: "CONTENTS-LIMIT", message: "The basic program covers belongings up to $50,000.", cite: manual:p2],
>             has_dog: Bool [ask: "Do you have a dog?", group: "Household"]
>         },
>         step rating [cite: manual:p2] {
>             dog_charge: Num = if self.has_dog then dog_surcharge else 0,
>             premium: Premium [cite: manual:p2] =
>                 round(self.contents / 1000 * rate_per_1000 + self.dog_charge, 0, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

Start a journey for both raters, and give each a title:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan start basket.json --rater renters=renters --rater basic=basic --title "renters=Renters" --title "basic=Renters Basic"
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.insured_now: Do you have a renters policy now?
  section: Insurance
  asked by: Renters
  still settled if skipped: 1
ready: none
```

`asked by` names the raters that declare the input, when some raters leave it out.
`still settled if skipped` counts the other raters whose result ignores the answer.
The two raters share the paths `Policy.contents` and `Policy.has_dog`, so one answer serves both.

## Put a card off

A person who lacks an answer puts the card off. Skip the path of the card:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan skip basket.json Policy.insured_now
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
number Policy.contents: What are your belongings worth?
  section: Home
  help: Count furniture, clothing and electronics.
  min: 10000
  max: 100000
ready: none
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer basket.json Policy.contents 30000
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.has_dog: Do you have a dog?
  section: Household
ready: none
```

`Renters` waits on the skipped answer, so the planner first asks what `Renters Basic` needs.

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer basket.json Policy.has_dog false
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
choice Policy.territory: Where is the home?
  section: Home
  still settled if skipped: 1
  - "metro": Metro
  - "suburban": Suburban
  - "rural": Rural
ready: basic
```

`Renters Basic` is ready after two answers. The remaining cards belong to `Renters`.
A skipped card comes back after the other cards, marked `(skipped before)`:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan answer basket.json Policy.territory '"rural"'
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.insured_now: Do you have a renters policy now?
  section: Insurance
  still settled if skipped: 1
  (skipped before)
ready: basic
```

To print the current card again, run `rslc plan next`. It leaves the journey as it is:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan next basket.json
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.insured_now: Do you have a renters policy now?
  section: Insurance
  still settled if skipped: 1
  (skipped before)
ready: basic
```

## Search the answers of a card

To find an answer in a long list, search the card's path:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan search basket.json sub --path Policy.territory
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
"suburban": Suburban
```

Each query word matches the start of a word in a label.
A `search` card holds a list too long to print, and this command finds its answers.

## Decline a document

The renters rater names a document with two annotations. `gives` says who has a declarations page, and `found_on` says that the page prints `contents`.
The planner offers the document as a card:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan start documents.json --rater renters=renters
rslc plan answer documents.json Policy.insured_now true
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
yesno Policy.insured_now: Do you have a renters policy now?
  section: Insurance
ready: none
document document:declarations_page:
  section: Home
  help: declarations page
ready: none
```

A host that reads documents saves the answers it finds as facts. To go on with the questions, dismiss the document:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc plan dismiss documents.json declarations_page
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
number Policy.contents: What are your belongings worth?
  section: Home
  help: Count furniture, clothing and electronics.
  min: 10000
  max: 100000
ready: none
```

## Drive a journey from Python

`Journey.plan` returns the same plan as `rslc plan --json`, for facts that your program holds:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
from rslc.journey import answer

person = {
    "Policy.insured_now": False,
    "Policy.contents": 30000,
    "Policy.territory": "metro",
    "Policy.construction": "masonry",
    "Policy.has_dog": False,
}
facts = {"Policy": {}}
step = journey.plan(facts)
while step["next"]:
    card = step["next"]
    print(card["kind"], card["path"], card["text"])
    facts = answer(facts, card["path"], person[card["path"]])
    step = journey.plan(facts, after=card["path"])
print(step["ready"], journey.evaluations(facts)["renters"]["settled"]["outputs"])
# yesno Policy.insured_now Do you have a renters policy now?
# number Policy.contents What are your belongings worth?
# choice Policy.territory Where is the home?
# choice Policy.construction How is the building built?
# yesno Policy.has_dog Do you have a dog?
# ['renters'] {'Policy': {'premium': 207}}
```

* `answer` returns a copy of the facts with one more answer.
* `after` names the card answered last, so the planner stays in its section.
* `step["next"]` is `None` when the plan has zero open cards. `step["standings"]` then gives the state of each rater.

## Related

* [Planner](https://docs.canary.effectiveai.app/rsl/reference/planner.md) lists each command, each `Journey` method and each field of a plan.
* [Missing answers](https://docs.canary.effectiveai.app/rsl/explanation/missing-answers.md) explains why a rater names the inputs that still matter.
* [Ask the questions a rater needs](https://docs.canary.effectiveai.app/rsl/tutorial/ask-questions.md) writes the `ask`, `help` and `group` annotations that a card shows.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.