5.5K+ RL tasks for hill-climbing small models in code and data science.
A 2B model on these tasks. Left: what it optimises. Right: 144 held-out tasks it never trains on.
Two runs over the same 5,000 tasks: shuffled against a curriculum ordered easiest to hardest.
Data-analysis tasks as a plain, load-and-go dataset: no runtime, no framework required. Each row is one self-contained task: a real tabular dataset, a question about it, and a gold answer a bundled grader can check deterministically. Load it, prompt any model however you like, grade the result.
This is the front door. If you want the tasks as runnable sandboxed environments, use the
Harbor suites; if you want
demonstrations to fine-tune on, use -sft.
| Split | Tasks | Easy | Medium | Hard | What it's for |
|---|---|---|---|---|---|
train | 5,000 | 1,433 | 2,845 | 722 | training |
test | 250 | 33 | 118 | 99 | held-out benchmark, deliberately harder |
eval | 144 | 16 | 74 | 54 | quick validation during a run |
The held-out splits are harder than train by construction: train is 29% easy and 14% hard, the held-out splits are 11β13% easy and 38β40% hard. Worth knowing before you read any eval number.
| Column | Meaning |
|---|---|
task_id, source_row_id | identifiers |
question | the question to answer |
answer | the gold answer |
reward_mode, atol, rtol | how to grade it: match type and numeric tolerances |
difficulty_level (1β5), difficulty_tier | difficulty |
kaggle_dataset | the source dataset |
hf_bucket, bucket_prefix, files | where the input files live and what they are |
instruction | the full agent prompt |
package_tier | environment sizing hint |
from datasets import load_dataset
ds = load_dataset("FineEnvs/SmolDataEnvs", split="test")
row = ds[0]
print(row["question"], "β", row["answer"], f"({row['reward_mode']})")
The tables live in a Hugging Face bucket, so they come down with the bucket API rather than
snapshot_download:
from huggingface_hub import list_bucket_tree, download_bucket_files
prefix = row["bucket_prefix"].rstrip("/") + "/"
items = [i for i in list_bucket_tree(row["hf_bucket"], prefix=prefix, recursive=True)
if getattr(i, "type", None) == "file"]
download_bucket_files(row["hf_bucket"],
files=[(i.path, "input/" + i.path.split("/")[-1]) for i in items])
grader.py ships in this repo. It scores an answer through a ladder of checks: exact β numeric
with atol/rtol β list and percent normalisation β symbolic equivalence:
from huggingface_hub import hf_hub_download
import importlib.util, sys
path = hf_hub_download("FineEnvs/SmolDataEnvs", "grader.py", repo_type="dataset")
spec = importlib.util.spec_from_file_location("grader", path)
grader = importlib.util.module_from_spec(spec)
sys.modules["grader"] = grader # the dataclasses inside it need this
spec.loader.exec_module(grader)
r = grader.grade(row["answer"], my_prediction, reward_mode=row["reward_mode"],
abs_tol=row["atol"], rel_tol=row["rtol"])
print(r.reward, r.method) # 1.0 exact | 0.0 miss
Built from the jupyter-agent dataset, real data-science notebooks over 471 Kaggle datasets. Every questionβanswer pair was extracted and then verified: strong agent models had to solve the task in a live sandbox and reproduce the gold answer under deterministic grading. Anything ambiguous or un-checkable was dropped. So every task here is known-solvable and unambiguously gradable.
Verified by a checker, not judged by a model. Grading is an exact comparison against a known answer, through a ladder of checks: exact match β numeric with tolerances β list and percent normalisation β symbolic equivalence. No LLM sits in the reward path, so the signal does not drift when you change the grader's model, because there isn't one.
| Repo | What it is |
|---|---|
SmolDataEnvs | the tasks as plain rows, load it and prompt any model |
SmolDataEnvs-sft | 4,677 verified agent trajectories, TRL-ready |
SmolDataEnvs-harbor-train | 5,000 tasks as Harbor environments |
SmolDataEnvs-harbor-test | 250 held-out, deliberately harder |
SmolDataEnvs-harbor-eval | 144 for quick validation during a run |
The simplest path, a notebook and a single-file script you can hand to HF Jobs, lives in FineEnvs/04-smoldataenvs.
@misc{fineenvs,
author = {Kolavi, Adithya S},
title = {FineEnvs: Open Source RL Environments for LLM Agents},
year = {2026},
url = {https://github.com/adithya-s-k/FineEnvs}
}
13 commits
5.5K+ RL tasks for hill-climbing small models in code and data science.
A 2B model on these tasks. Left: what it optimises. Right: 144 held-out tasks it never trains on.
Two runs over the same 5,000 tasks: shuffled against a curriculum ordered easiest to hardest.
Data-analysis tasks as a plain, load-and-go dataset: no runtime, no framework required. Each row is one self-contained task: a real tabular dataset, a question about it, and a gold answer a bundled grader can check deterministically. Load it, prompt any model however you like, grade the result.
This is the front door. If you want the tasks as runnable sandboxed environments, use the
Harbor suites; if you want
demonstrations to fine-tune on, use -sft.
| Split | Tasks | Easy | Medium | Hard | What it's for |
|---|---|---|---|---|---|
train | 5,000 | 1,433 | 2,845 | 722 | training |
test | 250 | 33 | 118 | 99 | held-out benchmark, deliberately harder |
eval | 144 | 16 | 74 | 54 | quick validation during a run |
The held-out splits are harder than train by construction: train is 29% easy and 14% hard, the held-out splits are 11β13% easy and 38β40% hard. Worth knowing before you read any eval number.
| Column | Meaning |
|---|---|
task_id, source_row_id | identifiers |
question | the question to answer |
answer | the gold answer |
reward_mode, atol, rtol | how to grade it: match type and numeric tolerances |
difficulty_level (1β5), difficulty_tier | difficulty |
kaggle_dataset | the source dataset |
hf_bucket, bucket_prefix, files | where the input files live and what they are |
instruction | the full agent prompt |
package_tier | environment sizing hint |
from datasets import load_dataset
ds = load_dataset("FineEnvs/SmolDataEnvs", split="test")
row = ds[0]
print(row["question"], "β", row["answer"], f"({row['reward_mode']})")
The tables live in a Hugging Face bucket, so they come down with the bucket API rather than
snapshot_download:
from huggingface_hub import list_bucket_tree, download_bucket_files
prefix = row["bucket_prefix"].rstrip("/") + "/"
items = [i for i in list_bucket_tree(row["hf_bucket"], prefix=prefix, recursive=True)
if getattr(i, "type", None) == "file"]
download_bucket_files(row["hf_bucket"],
files=[(i.path, "input/" + i.path.split("/")[-1]) for i in items])
grader.py ships in this repo. It scores an answer through a ladder of checks: exact β numeric
with atol/rtol β list and percent normalisation β symbolic equivalence:
from huggingface_hub import hf_hub_download
import importlib.util, sys
path = hf_hub_download("FineEnvs/SmolDataEnvs", "grader.py", repo_type="dataset")
spec = importlib.util.spec_from_file_location("grader", path)
grader = importlib.util.module_from_spec(spec)
sys.modules["grader"] = grader # the dataclasses inside it need this
spec.loader.exec_module(grader)
r = grader.grade(row["answer"], my_prediction, reward_mode=row["reward_mode"],
abs_tol=row["atol"], rel_tol=row["rtol"])
print(r.reward, r.method) # 1.0 exact | 0.0 miss
Built from the jupyter-agent dataset, real data-science notebooks over 471 Kaggle datasets. Every questionβanswer pair was extracted and then verified: strong agent models had to solve the task in a live sandbox and reproduce the gold answer under deterministic grading. Anything ambiguous or un-checkable was dropped. So every task here is known-solvable and unambiguously gradable.
Verified by a checker, not judged by a model. Grading is an exact comparison against a known answer, through a ladder of checks: exact match β numeric with tolerances β list and percent normalisation β symbolic equivalence. No LLM sits in the reward path, so the signal does not drift when you change the grader's model, because there isn't one.
| Repo | What it is |
|---|---|
SmolDataEnvs | the tasks as plain rows, load it and prompt any model |
SmolDataEnvs-sft | 4,677 verified agent trajectories, TRL-ready |
SmolDataEnvs-harbor-train | 5,000 tasks as Harbor environments |
SmolDataEnvs-harbor-test | 250 held-out, deliberately harder |
SmolDataEnvs-harbor-eval | 144 for quick validation during a run |
The simplest path, a notebook and a single-file script you can hand to HF Jobs, lives in FineEnvs/04-smoldataenvs.
@misc{fineenvs,
author = {Kolavi, Adithya S},
title = {FineEnvs: Open Source RL Environments for LLM Agents},
year = {2026},
url = {https://github.com/adithya-s-k/FineEnvs}
}
13 commits