Skip to main content
This page documents the operator-facing admin surface and the internal endpoints used between the master and its containers.
The /admin* and /v1/admin/* routes are gated by an admin token and are not public. The Docker broker and challenge get_weights endpoints are internal service-to-service routes — they are not exposed to end users.

Admin authentication

Every management route depends on require_admin, which reads the token from an X-Admin-Token header or from an Authorization: Bearer <token> credential and compares it in constant time (app_admin.py:121-130, auth.py:28-29). The expected value comes from the ADMIN_TOKEN environment variable, or from the file at ADMIN_TOKEN_FILE (auth.py:10-18). A mismatch returns 401 (app_admin.py:127-130).
curl -s "$MASTER_URL/v1/admin/challenges/agent-challenge" \
  -H "X-Admin-Token: $ADMIN_TOKEN"

Admin HTML pages

MethodPathReturnsSource
GET/adminHTML indexapp_admin.py:176-184
GET/admin/challengesHTML table of challengesapp_admin.py:186-200
Both depend on require_admin (app_admin.py:176, app_admin.py:186).

Challenge management routes

All routes below depend on require_admin.

POST /v1/admin/challenges

Creates a challenge. Returns 201 Created (app_admin.py:202-234). RequestChallengeCreate (schemas/challenge.py:22-41). Required fields: slug (pattern ^[a-z0-9][a-z0-9-]*[a-z0-9]$, schemas/challenge.py:25), name, image, version. Optional fields include emission_percent (default 0), status (default draft), description, api_version (default "1.0"), internal_base_url, required_capabilities (default ["get_weights", "proxy_routes"]), resources, volumes, env, secrets, and metadata (schemas/challenge.py:29-41). ResponseChallengeCreateResponse (schemas/challenge.py:131-136):
FieldTypeNotes
challengeobjectChallengeAdminView (schemas/challenge.py:106-128)
challenge_tokenstringClear token returned exactly once (schemas/challenge.py:135)
docker_broker_tokenstringBroker token returned exactly once (schemas/challenge.py:136)
A duplicate slug returns 409 (app_admin.py:214-218); an image that fails the production policy returns 400 (app_admin.py:219-220).
curl -s -X POST "$MASTER_URL/v1/admin/challenges" \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"slug":"agent-challenge","name":"Agent Challenge","image":"registry.example/agent:1.0","version":"1.0"}'

GET /v1/admin/challenges/{slug}

Returns a ChallengeAdminView (schemas/challenge.py:106-128); unknown slug returns 404 (app_admin.py:236-245).
curl -s "$MASTER_URL/v1/admin/challenges/agent-challenge" \
  -H "X-Admin-Token: $ADMIN_TOKEN"

PATCH /v1/admin/challenges/{slug}

Updates mutable metadata and returns a ChallengeAdminView (app_admin.py:247-264). RequestChallengeUpdate; all fields optional (schemas/challenge.py:51-67).
curl -s -X PATCH "$MASTER_URL/v1/admin/challenges/agent-challenge" \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"emission_percent":"25"}'

Status transitions

MethodPathResultSource
POST/v1/admin/challenges/{slug}/activatesets status activeapp_admin.py:266-277
POST/v1/admin/challenges/{slug}/deactivatesets status inactiveapp_admin.py:279-290
Both return a ChallengeAdminView (schemas/challenge.py:106-128).
curl -s -X POST "$MASTER_URL/v1/admin/challenges/agent-challenge/activate" \
  -H "X-Admin-Token: $ADMIN_TOKEN"

Runtime control

MethodPathOperationSource
POST/v1/admin/challenges/{slug}/pullpullapp_admin.py:304-310
POST/v1/admin/challenges/{slug}/restartrestartapp_admin.py:312-318
GET/v1/admin/challenges/{slug}/statusstatusapp_admin.py:320-326
All three return a RuntimeOperationResponse (schemas/challenge.py:168-174):
FieldType
slugstring
operationstring
statusstring
detailstring or null
curl -s -X POST "$MASTER_URL/v1/admin/challenges/agent-challenge/restart" \
  -H "X-Admin-Token: $ADMIN_TOKEN"

Internal service endpoints

The following routes are internal — they run on separate service apps and are authenticated with per-challenge tokens, not the admin token. They are documented here for operators; they are not part of the public API.

Docker broker (internal)

The Docker broker runs as its own app (docker_broker.py:653-659). Each request is authenticated with Authorization: Bearer <broker token> plus an X-Platform-Challenge-Slug header (_authenticate, docker_broker.py:717-730).
MethodPathRequestResponseSource
POST/v1/docker/runBrokerRunRequestBrokerRunResponsedocker_broker.py:669-690
POST/v1/docker/cleanupBrokerCleanupRequestBrokerCleanupResponsedocker_broker.py:692-701
POST/v1/docker/listBrokerListRequestBrokerListResponsedocker_broker.py:703-712
POST /v1/docker/run returns 429 when a workload quota is exceeded (docker_broker.py:685-688) and 400 on an executor error (docker_broker.py:689-690). BrokerRunResponse carries container_name, stdout, stderr, returncode, and timed_out (schemas/docker_broker.py:51-56); BrokerCleanupResponse carries status (schemas/docker_broker.py:82-83); BrokerListResponse carries containers (schemas/docker_broker.py:74-75).

Challenge weights collection (internal)

The master collects per-challenge weights by calling each challenge’s GET /internal/v1/get_weights, authenticated with the challenge’s bearer token and an X-Platform-Challenge-Slug header (challenge_client.py:31-36). The challenge replies with a ChallengeWeightsResponse (challenge_client.py:43; see Weights schema).

Security model

How the admin token gates these management routes.

Broker

The internal Docker broker documented on this page.

API overview

The full endpoint map and authentication models.