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

# Single-turn environments

> Write an EnvironmentSingleTurn class: dataset, prompt builder, and reward.

A single-turn environment resolves each example in one model response - prompt
in, completion out, reward computed. You implement a prompt builder and a reward
on an `EnvironmentSingleTurn` subclass.

Import these public names in environment code:

```python theme={null}
from freesolo.datasets import TaskExample
from freesolo.datasets.records import load_task_examples
from freesolo.environments import (
    EnvironmentEpisode,
    EnvironmentMultiTurn,
    EnvironmentStepResult,
    EnvironmentSingleTurn,
    RewardResult,
)
```

For a single-turn task, subclass `EnvironmentSingleTurn`:

```python environment.py theme={null}
from pathlib import Path

from freesolo.datasets import TaskExample
from freesolo.datasets.records import load_task_examples
from freesolo.environments import EnvironmentSingleTurn, RewardResult

ROOT = Path(__file__).parent

class MathEnv(EnvironmentSingleTurn):
    def __init__(self, *, split: str = "train") -> None:
        self.dataset = load_task_examples(ROOT / "dataset" / f"{split}.jsonl")

    def build_prompt_messages(self, example: TaskExample, prompt_text: str):
        return [{"role": "user", "content": example.input}]

    def score_response(self, example: TaskExample, response_text: str) -> RewardResult:
        expected = str(example.output or "").strip()
        score = 1.0 if expected and expected in response_text else 0.0
        return RewardResult(score=score, threshold=1.0)

def load_environment(split: str = "train", **kwargs) -> MathEnv:
    return MathEnv(split=split)
```

The dataset file uses the `input`/`output` row shape ([Task
records](/guides/datasets#task-records)). `load_task_examples(...)` exposes each
record's `input`/`output` as `example.input`/`example.output`, with the raw row
available as `example.record`.

For SFT, the SDK builds the training conversation from the environment's
`start_episode(example, prompt_text)` plus `sft_completion(example)`. The default
`sft_completion` converts `example.output` into completion messages. See
[Datasets](/guides/datasets#message-shaped-sft-targets) for the scalar and
message-shaped output forms. Override `sft_completion` only when the gold
completion must be synthesized from other fields.

Single-turn environments usually implement `build_prompt_messages`. The SDK's
default `start_episode` calls it and prepends the run's prompt text as a
`system` message when your messages lack one, so local eval, SFT, and GRPO see
the same policy prompt. Multi-turn environments own `start_episode`; put any
task-specific initial system message there. On managed runs, Flash applies the
same guarantee to every episode's opening messages, single- and multi-turn: if
`start_episode` returns no system message (or an empty one), the run's prompt
text becomes the system message.

When a run uses `thinking = true`, `score_response` receives answer text by
default. `response_text` stays string-compatible and also exposes
`response_text.completion`, `response_text.thinking`, and `response_text.raw` for
rewards that inspect the reasoning trace.

## Pass parameters

If your `load_environment(**kwargs)` accepts arguments, set them under
`[environment.params]`:

```toml theme={null}
[environment]
id = "your-org/your-env"

[environment.params]
difficulty = "hard"
num_examples = 500
```

## Next steps

<CardGroup cols={2}>
  <Card title="Multi-turn environments" icon="comments" href="/guides/environments/multi-turn">
    Handle conversations, tools, and agents.
  </Card>

  <Card title="Datasets" icon="table" href="/guides/datasets">
    Row shapes and SFT target formats.
  </Card>
</CardGroup>
