Docs · Main track · Submission format

DocsMain track

Submission format

What goes in the archive, how each solver is run, and the environment it runs in.

View as MarkdownThis page as plain text
llms.txtIndex of every docs page, for agents

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.

layout
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 with python. 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_Store files, 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
ArgumentValue
--problemThe problem's slug.
--instancePath to the instance file: JSON in the problem's instance schema. Read-only.
--outputWhere to write the solution file. See The solution file.
--time-limitThe 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

VariableValue
SANDBOX_PROBLEMThe problem's slug.
SANDBOX_TIMEOUT_SThe time limit in seconds, the same as --time-limit.
OMP_NUM_THREADS2, matching the CPU limit.
HOME/tmp
PYTHONUNBUFFERED, PYTHONDONTWRITEBYTECODE1
PATH, VIRTUAL_ENVPoint 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.

ResourceLimit
CPU2 vCPU (x86-64)
Memory4 GB, no swap. Going over ends the run.
TimeThe instance's time limit: 10 s, 60 s or 5 min, by the problem's time class.
Disk1 GB for /work. Only /work/out and /tmp (64 MB) are writable.
NetworkNone.
Processes256 processes and threads, 1,024 open files.
UserAn 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.
solution.json · barnhart2000
{
  "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.

Every installed packagewith the exact versions
PackagePython 3.12Python 3.14
absl-py2.5.02.5.0
annotated-types0.8.00.8.0
cpsat-logutils1.0.01.0.0
highspy1.15.11.15.1
immutabledict4.3.14.3.1
networkx3.73.7
numpy2.5.32.5.3
orloge1.0.01.0.0
ortools9.15.67559.15.6755
pandas3.0.63.0.6
protobuf6.33.66.33.6
pulp4.0.04.0.0
pydantic2.13.52.13.5
pydantic-core2.46.52.46.5
pyomo6.10.16.10.1
python-dateutil2.9.0.post02.9.0.post0
scipy1.18.11.18.1
six1.17.01.17.0
typing-extensions4.16.04.16.0
typing-inspection0.4.40.4.4

The lock files themselves are in GET /images.

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, -e or -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.
What is refused, and the message you get
LineMessage
Ends with \Line continuations aren't accepted. Put each package on one line.
Starts with -Options such as -i, -e or -r aren't accepted. Packages come from PyPI.
A URL, path, VCS link or archiveLinks, paths and archive files aren't accepted. Use the package's name on PyPI.
Anything else unreadableNot a package name with optional extras and versions, such as pyscipopt==5.5.0.
A bad marker after ;Not a valid environment marker after ";", such as sys_platform == "linux".
More than 50 packagesn packages; the limit is 50.
Longer than 10 KBThe list is longer than 10 KB.

Each message names its line.

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.