# Example code

> The starter repository and a standalone Python client.

Source: <https://frontieror-challenge.com/docs/self-hosted/example-code>

## The starter repository

[Alpha-Z-Pte-Ltd/frontieror-challenge-starter](https://github.com/Alpha-Z-Pte-Ltd/frontieror-challenge-starter) works for both tracks. It downloads the problems, lets an example agent write a solver for each, tests them on the public instances, and submits. Setup and commands are on the Main track's [Example code](https://frontieror-challenge.com/docs/main/example-code) page.

For a Self-hosted team, `uv run frontieror submit` runs the whole session:

1. It opens a submission, or resumes the one already open.
2. For each instance it has a solver for (`solvers/<slug>/solve.py`), it starts the instance, runs the solver on your machine and uploads the solution.
3. It finishes the submission.

Instances without a solver are not started, and score 0. The solver is called as on the Main track: `python solve.py --problem … --instance … --output … --time-limit …`.

## A standalone Python client

The same session in one script, for your own solver. It needs `httpx` and your API token in `FRONTIEROR_TOKEN`. Replace `solve` with your solver.

`self_hosted.py`

```python
import os
from datetime import datetime

import httpx

api = httpx.Client(
    base_url="https://frontieror-challenge.com/api/v1",
    headers={"Authorization": f"Bearer {os.environ['FRONTIEROR_TOKEN']}"},
    timeout=60,
)


def check(response: httpx.Response) -> httpx.Response:
    if response.is_error:
        raise SystemExit(f"{response.status_code}: {response.json()['error']}")
    return response


def solve(slug: str, instance: dict, seconds: float) -> dict:
    """Your solver: return the solution as a dict with a numeric objective_value."""
    raise NotImplementedError


submission = check(api.post("/self-hosted/submissions")).json()
base = f"/self-hosted/submissions/{submission['id']}"
closed = False

for item in submission["instances"]:
    # Starting the instance downloads it and starts its clock.
    started = check(api.post(f"{base}/instances/{item['id']}"))
    deadline = datetime.fromisoformat(started.headers["Upload-Deadline"])
    print(item["problem_slug"], item["name"], "due", deadline)

    try:
        solution = solve(item["problem_slug"], started.json(), item["time_limit_s"] - 5)
    except Exception as error:
        print("  no solution:", error)
        continue

    result = check(api.put(f"{base}/instances/{item['id']}/solution", json=solution)).json()
    if result["submission_closed"]:
        closed = True
        break

if not closed:
    check(api.post(f"{base}/finish"))
```

It solves the instances one after another, starting each just before solving it, so no clock runs while another instance is being solved. To solve several at once, start them together and run your solvers in parallel.

## Using any solver

On the Self-hosted track anything that runs on your machines is allowed, including commercial solvers and proprietary software. Only the solutions you upload are checked.
