A Main-track submission is one archive with a solver for each problem of the open round. We run each solver in a sandbox, once for every private instance of its problem, and check the solution file it writes.
The archive
Upload a zip, tar or tar.gz file of at most 4 MB. The format is read from the file's contents, so its name does not matter.
submission.zip
├── barnhart2000/ # one folder per problem, named by its slug
│ ├── solve.py # the entry point
│ ├── model.py # any other files the solver needs
│ └── params.json
└── <another-slug>/
└── solve.py
- One folder per problem of the open round, named exactly by the problem's slug. The slugs are on the dashboard and in
GET /problems. - One entry point per folder, directly inside it:
solve.py, which we run withpython. Solvers are Python only; for another language, use the Self-hosted track. - Each folder stands alone. A solver sees only its own folder, so code shared between problems has to be copied into every folder that uses it.
- A problem without a folder scores 0 on all of its instances. The upload form warns you and asks you to confirm; over the API, add
acknowledge_missing=1. - One wrapper folder is fine. If the whole layout sits inside a single folder, for example because you zipped the folder itself, that folder is skipped.
- Ignored:
__MACOSX/,.DS_Storefiles, and anything at the top level that is not a folder of an open-round problem. - Refused: symbolic and hard links, absolute paths, paths with
..or backslashes, more than 10,000 entries, or more than 256 MB unpacked.
How your solver is run
For every instance, the solver's folder is copied into a fresh sandbox and the entry point is started from inside it:
python solve.py --problem barnhart2000 \
--instance /work/in/instance.json \
--output /work/out/solution.json \
--time-limit 60
| Argument | Value |
|---|---|
--problem | The problem's slug. |
--instance | Path to the instance file: JSON in the problem's instance schema. Read-only. |
--output | Where to write the solution file. See The solution file. |
--time-limit | The instance's time limit in whole seconds. The sandbox stops the solver when it runs out. |
The working directory is /work/solver, which holds your problem folder and is read-only. Standard input is empty. Standard output and error are captured but not shown to you, since they could reveal the private instances.
Environment variables
| Variable | Value |
|---|---|
SANDBOX_PROBLEM | The problem's slug. |
SANDBOX_TIMEOUT_S | The time limit in seconds, the same as --time-limit. |
OMP_NUM_THREADS | 2, matching the CPU limit. |
HOME | /tmp |
PYTHONUNBUFFERED, PYTHONDONTWRITEBYTECODE | 1 |
PATH, VIRTUAL_ENV | Point at /opt/env when the submission has extra packages. |
Sandbox limits
Every instance runs alone on its own cores, so no other run shares its time.
| Resource | Limit |
|---|---|
| CPU | 2 vCPU (x86-64) |
| Memory | 4 GB, no swap. Going over ends the run. |
| Time | The instance's time limit: 10 s, 60 s or 5 min, by the problem's time class. |
| Disk | 1 GB for /work. Only /work/out and /tmp (64 MB) are writable. |
| Network | None. |
| Processes | 256 processes and threads, 1,024 open files. |
| User | An unprivileged user, uid 1000, with no capabilities. |
Finish before the limit. A solver still running at its time limit is stopped and the instance scores 0, even if it has already written a solution. Give your solver a time budget a few seconds under --time-limit, write the solution file and exit.
The solution file
Write one JSON object to the --output path, /work/out/solution.json, and exit with code 0.
- It follows the problem's solution schema, shown on each problem page. See Reading the schemas.
- It has a numeric
objective_value. The checker recomputes the objective from your decisions and rejects a solution whose claimed value does not match. - It is at most 16 MB.
{
"objective_value": 111,
"commodities": [
{ "commodity_id": 0, "rejected": true, "path_arcs": [] }
]
}
How a run turns into a score, and every message an instance can get, is on Evaluation and scoring.
Environment
Each submission runs in one environment, chosen when you submit. It is the same for every problem in the submission.
Our images
Python 3.12 (python-3.12, the default) or Python 3.14 (python-3.14), on Debian bookworm, with numpy, scipy, pandas, networkx, ortools, pulp, highspy and pyomo installed.
Extra packages
With our images you can add open-source packages from PyPI, one per line as in a requirements.txt, within the limits below:
pyscipopt==5.5.0
numba>=0.61
# a package you list replaces the image's version of it
numpy==2.4.1
- Up to 50 packages and 10 KB. Names, extras, version specifiers and environment markers are accepted.
- Packages come from PyPI by name only: no options such as
-i,-eor-r, and no URLs, paths, VCS links or wheel files. - They are installed once, before the first instance and outside every time limit, and mounted read-only. A later submission with the same image and list reuses them.
- An install that fails or takes longer than 10 min fails the submission, and its build log is shown on the dashboard.
The Main track allows open-source dependencies only. This is not checked automatically, but prize-eligible submissions are audited.
Checking before you submit
The starter repository runs your solvers the same way, in the same image and with the same limits:
uv run frontieror test --docker
It checks the run and the solution's format on the public instances, then feasibility with the problem's checker when it is published. Scores come only from a submission.