Sandbox API

Metric

Metric API endpoints

Metric API endpoints

Every request needs a credential — see Authentication.

MethodPathSummary
POST/sandbox/metric/metric/judgeRun an agentic judge over an arbitrary subject directory.
POST/sandbox/metric/metric/judge-batchRun an agentic judge over an arbitrary subject directory for N rubrics in parallel.
POST/sandbox/metric/metric/judge-batch/asyncEnqueue a batched agentic judge job and return immediately.
POST/sandbox/metric/metric/judge/asyncEnqueue an agentic judge job and return immediately.
GET/sandbox/metric/metric/judge/async/{job_id}Poll an async judge job for status / result.
POST/sandbox/metric/metric/judge/async/{job_id}/cancelCancel an in-flight async judge job.
POST/sandbox/metric/metric/prompt-rewardAlias of POST /metric/score-prompt-reward
POST/sandbox/metric/metric/score-average-rewardAverage reward → 1–10 score
POST/sandbox/metric/metric/score-behavior-correctnessScore whether tests check behavior vs implementation details
POST/sandbox/metric/metric/score-determinismScore determinism across reruns
POST/sandbox/metric/metric/score-documentationScore completeness of instruction.md documentation
POST/sandbox/metric/metric/score-edge-coverageScore the fraction of tests that target edge cases
POST/sandbox/metric/metric/score-false-negative-riskScore risk that a correct implementation fails the tests
POST/sandbox/metric/metric/score-false-positive-riskScore risk that a wrong implementation passes the tests
POST/sandbox/metric/metric/score-leakage-heuristicStatic heuristic for instruction/tests leakage
POST/sandbox/metric/metric/score-model-breakingScore candidate as model-breaking
POST/sandbox/metric/metric/score-oracleScore the oracle agent run
POST/sandbox/metric/metric/score-prompt-rewardInfer difficulty + score from oracle vs candidate
POST/sandbox/metric/metric/score-real-world-applicabilityScore how representative the task is of real-world work
POST/sandbox/metric/metric/score-test-alignmentScore how well tests/ aligns with instruction.md
POST/sandbox/metric/metric/test-qualityAlias of POST /metric/score-test-alignment

Common headers

Accepted on every endpoint on this page.

NameInTypeRequiredDescription
x-correlation-idheaderstringnoEnd-to-end correlation id for this eval run. When set, the gateway and downstream services honor it verbatim in logs, Cloud Trace span attributes, async job payloads, and Langfuse trace.id. When omitted, the gateway generates a ULID and echoes it on the response.

Endpoints

Run an agentic judge over an arbitrary subject directory.

POST /sandbox/metric/metric/judge

Request body

application/json, required — JudgeMetricRequest

FieldTypeRequiredDescription
promptstringyesFull rubric / system prompt the judge agent receives. Written verbatim to /inputs/rubric.md inside the judge container.
rubric_labelstring | nullnoShort human-readable label surfaced in worker logs and the result envelope (e.g. "test-alignment"). Defaults to a label derived from the subject source.
output_schemaobject | nullnoOptional JSON Schema validated against the agent's judgment.json inside the verifier. When set, judgment.json MUST validate or the worker returns JudgeOutputInvalid.
extra_contextstring | nullnoOptional free-form context appended to the agent's instruction.md. Useful for dataset version, locale, etc.
subject_bundleobject | nullnoInline path → UTF-8 text map. Same shape as collect_task_bundle_from_task_dir; skips remote fetch.
subject_archive_urlstring | nullnoHTTPS URL returning either a zip archive of the subject tree OR a single file (PDF, image, document, ...). Zip payloads are extracted into /inputs/subject/ on the worker; single-file payloads are saved at /inputs/subject/<basename> so the judge agent can evaluate either shape without code changes. JSON aliases: subject_url, task_archive_url.
subject_manifest_urlstring | nullnoLegacy CTP / GDPval _manifest.json URL. Rejected on the platform (400): zip the files and send subject_archive_url. JSON aliases: manifest_url, task_manifest_url.
subject_manifest_expires_atstring | nullnoLegacy deadline for subject_manifest_url; only valid with it, so also unsupported on the platform.
subject_storage_resourcestring | nullnoLegacy Drive / S3 / GCS storage location. Rejected on the platform (400): send a presigned HTTPS URL (zip or single file) as subject_archive_url. JSON alias: storage_resource.
subject_storage_connector_idinteger | nullnoLegacy TI storage connector id; only valid with subject_storage_resource, so also unsupported on the platform. JSON alias: storage_connector_id.
subject_task_slugstring | nullnoLegacy local task slug. Rejected on the platform (400): the worker has no task tree. JSON alias: task_slug.
judge_agentstring | nullnoOverride for the Harbor agent name to run as the judge (e.g. claude-code, openhands). Defaults to the worker's configured default.
modelstring | nullnoOverride for the model id passed to the judge agent. Defaults to the worker's configured default model.
timeout_secnumber | nullnoWall-clock cap for the judge Harbor invocation. Worker may clamp this to a configured maximum.
sandbox"asg" | "k8s" | "daytona" | "docker" | "prism" | nullnoPer-request Harbor sandbox/environment override for this judge trial. Mirrors the agent service's RunDatapointRequest.sandbox so callers learn one vocabulary across both endpoints. When omitted, the worker uses its configured SANDBOX_METRIC_SANDBOX default. Values: asg is a routing hint — by the time the worker runs the trial, asg is collapsed to 'no override' (the worker is already the destination). k8s selects the K8s-Job sandbox for this trial only (cluster bits must be installed). daytona selects the Daytona SDK. docker selects the local Docker provider (needs a Docker socket on the worker host).
credential_sourcestring | nullnoOptional per-request override of SANDBOX_METRIC_CREDENTIAL_SOURCE (registry | prism | registry_with_prism_fallback | litellm | llmgateway | registry_with_llmgateway_fallback). llmgateway prefers gateway_workspace + gateway_project with platform llm_egress M2M (no body tk_live_). Legacy inline credentials.llmgateway.api_key remains accepted during soak.
gateway_workspacestring | nullnoLLM Gateway workspace slug (x-llmcp-workspace). Stamped by Prism when credential_source=llmgateway; required with gateway_project for M2M egress without a body tk_live_.
gateway_projectstring | nullnoLLM Gateway project slug (x-llmcp-project). Stamped by Prism when credential_source=llmgateway; required with gateway_workspace for M2M egress without a body tk_live_.
credentialsJobCredentialsSpec | nullnoPer-request credential overrides (RFC 0010 §6). Inline env / api_key are never persisted to S3. Prefer omitting credentials.llmgateway.api_key and stamping gateway workspace/project for platform M2M; legacy api_key + base_url remain accepted during soak.

Example:

{
  "prompt": "Identify any leakage between `/inputs/subject/instruction.md` and `/inputs/subject/tests/`. Write /outputs/judgment.json.",
  "subject_archive_url": "https://storage.example.com/tasks/candidate.zip",
  "rubric_label": "leakage-check",
  "output_schema": {
    "type": "object",
    "required": [
      "score",
      "explanation",
      "details"
    ],
    "properties": {
      "score": {
        "type": "number",
        "minimum": 0,
        "maximum": 1
      },
      "explanation": {
        "type": "string"
      },
      "details": {
        "type": "object"
      }
    }
  },
  "timeout_sec": 1200
}

Responses

StatusDescriptionBody
200Agentic judge completed; parsed Judgment + metadata.JudgeMetricResponse
400Caller-side input is the problem: the subject is not an inline bundle or archive URL (task slugs, manifests and Drive/TI resources are not supported on the platform).—
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—
499Client disconnected; judge run cancelled.—
502Worker- or judge-agent-side failure: subject couldn't be materialized, sandbox refused to start, or the judge agent's judgment.json didn't validate against output_schema.—
503Worker fleet unavailable, per-pod concurrency cap hit, or admission preflight rejected the requested sandbox.—

Example response:

{
  "score": 0.85,
  "explanation": "Tests align with instruction in 4 of 5 cases; one assertion checks output formatting not described in instruction.md.",
  "details": {
    "covered_requirements": 4,
    "total_requirements": 5,
    "missing_coverage": [
      "formatting of trailing newline"
    ]
  },
  "subject_label": "test-alignment",
  "judge_agent": "claude-code",
  "model_used": "anthropic/claude-haiku-4-5",
  "duration_sec": 38.7,
  "telemetry": {
    "model": "anthropic/claude-haiku-4-5",
    "prompt_tokens": 12400,
    "completion_tokens": 890,
    "cache_tokens": 3200,
    "total_tokens": 13290,
    "latency_ms": 38700,
    "cost_usd": 0.042
  }
}

Run an agentic judge over an arbitrary subject directory for N rubrics in parallel.

POST /sandbox/metric/metric/judge-batch

Request body

application/json, required — JudgeBatchRequest

FieldTypeRequiredDescription
subjectJudgeBatchSubjectyesShared subject under evaluation; one source per request.
rubricsJudgeBatchRubricRequest[]yesOrdered list of rubrics. Response preserves this order. Length is capped at the route layer (metric.judgeBatchMaxRubrics).
judge_agentstring | nullnoBatch-level default agent; per-rubric overrides take precedence.
modelstring | nullnoBatch-level default model; per-rubric overrides take precedence.
timeout_secnumber | nullnoBatch-level default per-rubric timeout.
sandbox"asg" | "k8s" | "daytona" | "docker" | "prism" | nullnoPer-batch sandbox override. Same vocabulary as the singleton endpoint; the entire batch runs in one sandbox.
credential_sourcestring | nullnoOptional per-batch override of SANDBOX_METRIC_CREDENTIAL_SOURCE (registry | prism | registry_with_prism_fallback | litellm | llmgateway | registry_with_llmgateway_fallback).
gateway_workspacestring | nullnoLLM Gateway workspace slug (x-llmcp-workspace). Stamped by Prism when credential_source=llmgateway; required with gateway_project for M2M egress without a body tk_live_.
gateway_projectstring | nullnoLLM Gateway project slug (x-llmcp-project). Stamped by Prism when credential_source=llmgateway; required with gateway_workspace for M2M egress without a body tk_live_.
credentialsJobCredentialsSpec | nullnoPer-batch credential overrides (RFC 0010 §6). Inline env / api_key are never persisted to S3. Prefer omitting credentials.llmgateway.api_key and stamping gateway workspace/project for platform M2M; legacy api_key + base_url remain accepted during soak.

Example:

{
  "subject": {
    "archive_url": "https://storage.example.com/tasks/candidate.zip"
  },
  "rubrics": [
    {
      "label": "test-alignment",
      "prompt": "Score test alignment on 0..1."
    },
    {
      "label": "leakage-check",
      "prompt": "Identify leakage between instruction and tests."
    }
  ],
  "judge_agent": "claude-code",
  "model": "anthropic/claude-haiku-4-5",
  "timeout_sec": 600
}

Responses

StatusDescriptionBody
200Per-rubric results in request order plus batch-level timing. Per-rubric failures populate error slots; the response remains HTTP 200 as long as the batch reached the fan-out phase.JudgeBatchResponse
400Request rejected at the route layer — typically because rubrics exceeds the configured per-batch cap.—
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—
499Client disconnected; judge run cancelled.—
502Whole-batch failure (subject can't be materialized or sandbox refused to start). Per-rubric failures are surfaced as error slots in a 200 response instead.—
503Worker fleet unavailable, per-pod concurrency cap hit, or admission preflight rejected the requested sandbox.—

Example response:

{
  "results": [
    {
      "label": "test-alignment",
      "score": 0.9,
      "explanation": "All instruction requirements have matching test assertions.",
      "details": {
        "covered_requirements": 5,
        "total_requirements": 5
      },
      "judge_agent": "claude-code",
      "model_used": "anthropic/claude-haiku-4-5",
      "duration_sec": 33.4,
      "telemetry": {
        "model": "anthropic/claude-haiku-4-5",
        "prompt_tokens": 12400,
        "completion_tokens": 890,
        "cache_tokens": 3200,
        "total_tokens": 13290,
        "latency_ms": 38700,
        "cost_usd": 0.042
      }
    },
    {
      "label": "leakage-check",
      "score": 0.95,
      "explanation": "No leakage detected between instruction and tests.",
      "details": {
        "leakage_signals": []
      },
      "judge_agent": "claude-code",
      "model_used": "anthropic/claude-haiku-4-5",
      "duration_sec": 28.7,
      "telemetry": {
        "model": "anthropic/claude-haiku-4-5",
        "prompt_tokens": 12400,
        "completion_tokens": 890,
        "cache_tokens": 3200,
        "total_tokens": 13290,
        "latency_ms": 38700,
        "cost_usd": 0.042
      }
    }
  ],
  "subject_label": "hello-world",
  "shared_setup_duration_sec": 12.4,
  "batch_duration_sec": 41.1
}

Enqueue a batched agentic judge job and return immediately.

POST /sandbox/metric/metric/judge-batch/async

Request body

application/json, required — JudgeBatchRequest

FieldTypeRequiredDescription
subjectJudgeBatchSubjectyesShared subject under evaluation; one source per request.
rubricsJudgeBatchRubricRequest[]yesOrdered list of rubrics. Response preserves this order. Length is capped at the route layer (metric.judgeBatchMaxRubrics).
judge_agentstring | nullnoBatch-level default agent; per-rubric overrides take precedence.
modelstring | nullnoBatch-level default model; per-rubric overrides take precedence.
timeout_secnumber | nullnoBatch-level default per-rubric timeout.
sandbox"asg" | "k8s" | "daytona" | "docker" | "prism" | nullnoPer-batch sandbox override. Same vocabulary as the singleton endpoint; the entire batch runs in one sandbox.
credential_sourcestring | nullnoOptional per-batch override of SANDBOX_METRIC_CREDENTIAL_SOURCE (registry | prism | registry_with_prism_fallback | litellm | llmgateway | registry_with_llmgateway_fallback).
gateway_workspacestring | nullnoLLM Gateway workspace slug (x-llmcp-workspace). Stamped by Prism when credential_source=llmgateway; required with gateway_project for M2M egress without a body tk_live_.
gateway_projectstring | nullnoLLM Gateway project slug (x-llmcp-project). Stamped by Prism when credential_source=llmgateway; required with gateway_workspace for M2M egress without a body tk_live_.
credentialsJobCredentialsSpec | nullnoPer-batch credential overrides (RFC 0010 §6). Inline env / api_key are never persisted to S3. Prefer omitting credentials.llmgateway.api_key and stamping gateway workspace/project for platform M2M; legacy api_key + base_url remain accepted during soak.

Example:

{
  "subject": {
    "archive_url": "https://storage.example.com/tasks/candidate.zip"
  },
  "rubrics": [
    {
      "label": "test-alignment",
      "prompt": "Score test alignment on 0..1."
    },
    {
      "label": "leakage-check",
      "prompt": "Identify leakage between instruction and tests."
    }
  ],
  "judge_agent": "claude-code",
  "model": "anthropic/claude-haiku-4-5",
  "timeout_sec": 600
}

Responses

StatusDescriptionBody
202Job accepted; poll_url is pre-built for the matching status endpoint. On an idempotent replay the same job_id is returned.JudgeAsyncAcceptedResponse
400Same per-batch cap and validation as the sync routes — only applies to /metric/judge-batch/async.—
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—
503Worker fleet unavailable, per-pod concurrency cap hit, or admission preflight rejected the requested sandbox.—

Example response:

{
  "job_id": "8b1f3c2a-2c3d-4e5f-9012-abcdef012345",
  "request_id": "65c7f62a-c7aa-457e-9ec7-351510b76827",
  "status": "queued",
  "poll_url": "/metric/judge/async/8b1f3c2a-2c3d-4e5f-9012-abcdef012345"
}

Enqueue an agentic judge job and return immediately.

POST /sandbox/metric/metric/judge/async

Request body

application/json, required — JudgeMetricRequest

FieldTypeRequiredDescription
promptstringyesFull rubric / system prompt the judge agent receives. Written verbatim to /inputs/rubric.md inside the judge container.
rubric_labelstring | nullnoShort human-readable label surfaced in worker logs and the result envelope (e.g. "test-alignment"). Defaults to a label derived from the subject source.
output_schemaobject | nullnoOptional JSON Schema validated against the agent's judgment.json inside the verifier. When set, judgment.json MUST validate or the worker returns JudgeOutputInvalid.
extra_contextstring | nullnoOptional free-form context appended to the agent's instruction.md. Useful for dataset version, locale, etc.
subject_bundleobject | nullnoInline path → UTF-8 text map. Same shape as collect_task_bundle_from_task_dir; skips remote fetch.
subject_archive_urlstring | nullnoHTTPS URL returning either a zip archive of the subject tree OR a single file (PDF, image, document, ...). Zip payloads are extracted into /inputs/subject/ on the worker; single-file payloads are saved at /inputs/subject/<basename> so the judge agent can evaluate either shape without code changes. JSON aliases: subject_url, task_archive_url.
subject_manifest_urlstring | nullnoLegacy CTP / GDPval _manifest.json URL. Rejected on the platform (400): zip the files and send subject_archive_url. JSON aliases: manifest_url, task_manifest_url.
subject_manifest_expires_atstring | nullnoLegacy deadline for subject_manifest_url; only valid with it, so also unsupported on the platform.
subject_storage_resourcestring | nullnoLegacy Drive / S3 / GCS storage location. Rejected on the platform (400): send a presigned HTTPS URL (zip or single file) as subject_archive_url. JSON alias: storage_resource.
subject_storage_connector_idinteger | nullnoLegacy TI storage connector id; only valid with subject_storage_resource, so also unsupported on the platform. JSON alias: storage_connector_id.
subject_task_slugstring | nullnoLegacy local task slug. Rejected on the platform (400): the worker has no task tree. JSON alias: task_slug.
judge_agentstring | nullnoOverride for the Harbor agent name to run as the judge (e.g. claude-code, openhands). Defaults to the worker's configured default.
modelstring | nullnoOverride for the model id passed to the judge agent. Defaults to the worker's configured default model.
timeout_secnumber | nullnoWall-clock cap for the judge Harbor invocation. Worker may clamp this to a configured maximum.
sandbox"asg" | "k8s" | "daytona" | "docker" | "prism" | nullnoPer-request Harbor sandbox/environment override for this judge trial. Mirrors the agent service's RunDatapointRequest.sandbox so callers learn one vocabulary across both endpoints. When omitted, the worker uses its configured SANDBOX_METRIC_SANDBOX default. Values: asg is a routing hint — by the time the worker runs the trial, asg is collapsed to 'no override' (the worker is already the destination). k8s selects the K8s-Job sandbox for this trial only (cluster bits must be installed). daytona selects the Daytona SDK. docker selects the local Docker provider (needs a Docker socket on the worker host).
credential_sourcestring | nullnoOptional per-request override of SANDBOX_METRIC_CREDENTIAL_SOURCE (registry | prism | registry_with_prism_fallback | litellm | llmgateway | registry_with_llmgateway_fallback). llmgateway prefers gateway_workspace + gateway_project with platform llm_egress M2M (no body tk_live_). Legacy inline credentials.llmgateway.api_key remains accepted during soak.
gateway_workspacestring | nullnoLLM Gateway workspace slug (x-llmcp-workspace). Stamped by Prism when credential_source=llmgateway; required with gateway_project for M2M egress without a body tk_live_.
gateway_projectstring | nullnoLLM Gateway project slug (x-llmcp-project). Stamped by Prism when credential_source=llmgateway; required with gateway_workspace for M2M egress without a body tk_live_.
credentialsJobCredentialsSpec | nullnoPer-request credential overrides (RFC 0010 §6). Inline env / api_key are never persisted to S3. Prefer omitting credentials.llmgateway.api_key and stamping gateway workspace/project for platform M2M; legacy api_key + base_url remain accepted during soak.

Example:

{
  "prompt": "Identify any leakage between `/inputs/subject/instruction.md` and `/inputs/subject/tests/`. Write /outputs/judgment.json.",
  "subject_archive_url": "https://storage.example.com/tasks/candidate.zip",
  "rubric_label": "leakage-check",
  "output_schema": {
    "type": "object",
    "required": [
      "score",
      "explanation",
      "details"
    ],
    "properties": {
      "score": {
        "type": "number",
        "minimum": 0,
        "maximum": 1
      },
      "explanation": {
        "type": "string"
      },
      "details": {
        "type": "object"
      }
    }
  },
  "timeout_sec": 1200
}

Responses

StatusDescriptionBody
202Job accepted; poll_url is pre-built for the matching status endpoint. On an idempotent replay the same job_id is returned.JudgeAsyncAcceptedResponse
400Same per-batch cap and validation as the sync routes — only applies to /metric/judge-batch/async.—
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—
503Worker fleet unavailable, per-pod concurrency cap hit, or admission preflight rejected the requested sandbox.—

Example response:

{
  "job_id": "8b1f3c2a-2c3d-4e5f-9012-abcdef012345",
  "request_id": "65c7f62a-c7aa-457e-9ec7-351510b76827",
  "status": "queued",
  "poll_url": "/metric/judge/async/8b1f3c2a-2c3d-4e5f-9012-abcdef012345"
}

Poll an async judge job for status / result.

GET /sandbox/metric/metric/judge/async/{job_id}

Parameters

NameInTypeRequiredDescription
job_idpathstringyes
X-Sandbox-Project-Idheaderstring | nullnoProject to bill and rate-limit this request against. Validated against the credential: a project-scoped token may only name its own project, and gets 403 otherwise. Defaults to the token's project when omitted.
X-Sandbox-Tenant-Idheaderstring | nullnoTenant for this request. Must match the credential's tenant when the credential carries one.

Responses

StatusDescriptionBody
200Always 200 on a successful poll. Job success/failure encoded in the status + error / error_class fields. Use the embedded result envelope for the parsed judge outcome on status='succeeded'.JudgeAsyncStatusResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404No status.json exists in S3 for this job_id.—
422Validation ErrorHTTPValidationError
503Async poll endpoint not wired on this deployment (the agent package is not bundled into this metric image).—

Example response:

{
  "job_id": "8b1f3c2a-2c3d-4e5f-9012-abcdef012345",
  "status": "queued",
  "updated_at": "2026-05-19T15:04:01.123456+00:00"
}

Cancel an in-flight async judge job.

POST /sandbox/metric/metric/judge/async/{job_id}/cancel

Parameters

NameInTypeRequiredDescription
job_idpathstringyes
X-Sandbox-Project-Idheaderstring | nullnoProject to bill and rate-limit this request against. Validated against the credential: a project-scoped token may only name its own project, and gets 403 otherwise. Defaults to the token's project when omitted.
X-Sandbox-Tenant-Idheaderstring | nullnoTenant for this request. Must match the credential's tenant when the credential carries one.

Responses

StatusDescriptionBody
200S3 status.json is now cancelled. The worker confirms the cancel on its next watch-loop tick (~5 s).JudgeAsyncCancelResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404No status.json exists in S3 for this job_id.—
409Job already settled in a terminal-non-cancelled state — overwriting the terminal result is refused.—
422Validation ErrorHTTPValidationError
503Async poll endpoint not wired on this deployment (the agent package is not bundled into this metric image).—

Example response:

{
  "job_id": "8b1f3c2a-2c3d-4e5f-9012-abcdef012345",
  "status": "cancelled",
  "was_active": true
}

Alias of POST /metric/score-prompt-reward

POST /sandbox/metric/metric/prompt-reward

Compatibility alias for POST /metric/score-prompt-reward.

Request body

application/json, required — PromptRewardRequest

FieldTypeRequiredDescription
oracle_harbor_resultobject | nullnoHarbor job result for the oracle/reference agent (typically agent_results[0].result).
candidate_harbor_resultobject | nullnoHarbor job result for the candidate agent (typically agent_results[1].result).
harbor_job_resultsobject[] | nullnoFull agent results array (same shape as model_response / agent_response). Oracle and candidate entries are auto-extracted by name.
expected_output"easy" | "medium" | "hard" | "expert" | nullnoOptional difficulty label to compare against inferred difficulty. For harbor-task-pipeline jobs, supply this on the metric request body; it is not part of the pipeline input contract.

Example:

{
  "oracle_harbor_result": {
    "stats": {
      "n_trials": 1,
      "n_errors": 0,
      "evals": {
        "default": {
          "metrics": [
            {
              "mean": 1
            }
          ],
          "reward_stats": {
            "reward": {
              "1.0": [
                "t1"
              ]
            }
          },
          "n_errors": 0
        }
      }
    }
  },
  "candidate_harbor_result": {
    "stats": {
      "n_trials": 1,
      "n_errors": 0,
      "evals": {
        "default": {
          "metrics": [
            {
              "mean": 0
            }
          ],
          "reward_stats": {
            "reward": {
              "0.0": [
                "t1"
              ]
            }
          },
          "n_errors": 0
        }
      }
    }
  },
  "expected_output": "hard"
}

Responses

StatusDescriptionBody
200Prompt reward + inferred difficulty scored.PromptRewardResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—

Example response:

{
  "score": 10,
  "explanation": "Oracle mean 1.0, candidate mean 0.0; reward gap 1.0 → inferred 'hard'. Matches expected_output='hard'.",
  "difficulty": "hard",
  "difficulty_score": 1,
  "expected_output": "hard",
  "matches_expected": true,
  "oracle_mean_reward": 1,
  "candidate_mean_reward": 0
}

Average reward → 1–10 score

POST /sandbox/metric/metric/score-average-reward

Single Harbor job, or mean of per-agent job means (multi-agent / datapoint).

Request body

application/json, required — AverageRewardRequest

FieldTypeRequiredDescription
harbor_job_resultobject | nullnoOne Harbor job-level result.json (single agent). Omit when sending harbor_job_results.
harbor_job_resultsobject[] | nullnoOne Harbor job per agent: either raw result.json (top-level stats) or a datapoint row with the job nested under result (same shape as RunDatapointResponse.agent_results[]). Score is the mean of each job's average reward, then mapped to 1–10. Do not combine with harbor_job_result.
verifier_ctrfobject | nullnoOptional CTRF test report (from verifier/ctrf.json) for the single harbor_job_result. When present, per-test pass/fail details are included in the explanation.
verifier_ctrfsobject | null[] | nullnoOptional list of CTRF reports parallel to harbor_job_results (one per agent). When present, per-test pass/fail details are included in the explanation.
artifact_download_urlsArtifactDownloadUrlsPayload | nullnoOptional presigned artifact URLs from the datapoint run; echoed in score-average-reward explanation for convenience.

Example:

{
  "harbor_job_results": [
    {
      "stats": {
        "evals": {
          "a": {
            "metrics": [
              {
                "mean": 1
              }
            ],
            "reward_stats": {
              "reward": {
                "1.0": [
                  "t1"
                ]
              }
            },
            "n_errors": 0
          }
        }
      }
    },
    {
      "stats": {
        "evals": {
          "b": {
            "metrics": [
              {
                "mean": 0
              }
            ],
            "reward_stats": {
              "reward": {
                "0.0": [
                  "t1"
                ]
              }
            },
            "n_errors": 0
          }
        }
      }
    }
  ]
}

Responses

StatusDescriptionBody
200Average reward scored (single job or multi-agent pool).AverageRewardResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—

Example response:

{
  "score": 10,
  "explanation": "Mean reward 1.0 across 1 trial; mapped to 10.0 on the 1–10 scale.",
  "mean_reward": 1,
  "n_rewards": 1,
  "had_error": false
}

Score whether tests check behavior vs implementation details

POST /sandbox/metric/metric/score-behavior-correctness

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 9,
  "explanation": "Most tests assert observable behavior; few coupling to internal state or magic numbers.",
  "details": {
    "implementation_coupled_tests": [],
    "magic_number_tests": [],
    "behavior_correct_tests": [
      "test_output_lines",
      "test_exit_code",
      "test_handles_empty_input"
    ]
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Score determinism across reruns

POST /sandbox/metric/metric/score-determinism

Request body

application/json, required — DeterminismRequest

FieldTypeRequiredDescription
harbor_run_resultsobject[] | nullnoPre-assembled list of Harbor job result.json objects (main + reruns).
agent_resultsobject[] | nullnoFull agent_results array from RunDatapointResponse. The first entry's result key is used as the main run for determinism comparison.
determinism_rerun_resultsobject[] | nullnoExtra Harbor job result.json objects from determinism reruns of the first agent (top-level field from RunDatapointResponse).

Example:

{
  "harbor_run_results": [
    {
      "stats": {
        "n_trials": 1,
        "n_errors": 0,
        "evals": {
          "default": {
            "metrics": [
              {
                "mean": 1
              }
            ],
            "reward_stats": {
              "reward": {
                "1.0": [
                  "t1"
                ]
              }
            },
            "n_errors": 0
          }
        }
      }
    },
    {
      "stats": {
        "n_trials": 1,
        "n_errors": 0,
        "evals": {
          "default": {
            "metrics": [
              {
                "mean": 1
              }
            ],
            "reward_stats": {
              "reward": {
                "1.0": [
                  "t1"
                ]
              }
            },
            "n_errors": 0
          }
        }
      }
    },
    {
      "stats": {
        "n_trials": 1,
        "n_errors": 0,
        "evals": {
          "default": {
            "metrics": [
              {
                "mean": 1
              }
            ],
            "reward_stats": {
              "reward": {
                "1.0": [
                  "t1"
                ]
              }
            },
            "n_errors": 0
          }
        }
      }
    }
  ]
}

Responses

StatusDescriptionBody
200Determinism stability scored.DeterminismResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—

Example response:

{
  "score": 10,
  "explanation": "All 3 runs returned mean_reward=1.0; fully deterministic and passing.",
  "run_count": 3,
  "mean_rewards": [
    1,
    1,
    1
  ],
  "all_means_identical": true,
  "all_means_one": true
}

Score completeness of instruction.md documentation

POST /sandbox/metric/metric/score-documentation

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 9,
  "explanation": "Instruction lists every assertion in tests/, with input/output examples.",
  "details": {
    "missing_requirements": [],
    "undocumented_assertions": []
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Score the fraction of tests that target edge cases

POST /sandbox/metric/metric/score-edge-coverage

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 9,
  "explanation": "8 of 12 tests cover edge cases (66%); the test suite covers boundaries, empty inputs, and one concurrency case.",
  "details": {
    "edge_case_count": 8,
    "total_test_count": 12,
    "edge_fraction": 0.66,
    "edge_tests": [
      "test_empty_input",
      "test_max_int_boundary",
      "test_concurrent_writes"
    ],
    "missing_edge_cases": [
      "zero-length file",
      "unicode names"
    ]
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Score risk that a correct implementation fails the tests

POST /sandbox/metric/metric/score-false-negative-risk

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 9,
  "explanation": "Tests don't over-specify implementation details; a correct alternative implementation would pass.",
  "details": {
    "risk": "low",
    "top_risks": [
      "test depends on the exact order of dict keys in stdout (Python ≥3.7 only)"
    ]
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Score risk that a wrong implementation passes the tests

POST /sandbox/metric/metric/score-false-positive-risk

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 9,
  "explanation": "Tests assert specific behavior; unlikely to pass a buggy implementation.",
  "details": {
    "risk": "low",
    "top_risks": [
      "test relies on print formatting only — could miss a mis-rounded float"
    ]
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Static heuristic for instruction/tests leakage

POST /sandbox/metric/metric/score-leakage-heuristic

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200Heuristic leakage score (static; no LLM).ScoreOnlyResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled.—
422Request body failed Pydantic validation.—

Example response:

{
  "score": 10,
  "explanation": "No shared identifiers between instruction.md and the tests/ directory."
}

Score candidate as model-breaking

POST /sandbox/metric/metric/score-model-breaking

Request body

application/json, required — ModelBreakingRequest

FieldTypeRequiredDescription
harbor_job_resultobject | nullnoFull Harbor job-level result.json object (candidate / model-under-test run).
harbor_job_resultsobject[] | nullnoFull agent results array (same shape as model_response / agent_response). The candidate entry is auto-extracted by name.

Example:

{
  "harbor_job_result": {
    "stats": {
      "n_trials": 1,
      "n_errors": 0,
      "evals": {
        "default": {
          "metrics": [
            {
              "mean": 0
            }
          ],
          "reward_stats": {
            "reward": {
              "0.0": [
                "t1"
              ]
            }
          },
          "n_errors": 0
        }
      }
    }
  }
}

Responses

StatusDescriptionBody
200Model-breaking metric scored.ModelBreakingResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—

Example response:

{
  "score": 10,
  "explanation": "Candidate mean reward 0.0 over 1 trial; below the 0.05 threshold (model-breaking).",
  "pass_rate": 0,
  "n_trials": 1,
  "n_success_trials": 0,
  "threshold": 0.05,
  "had_error": false,
  "below_threshold": true
}

Score the oracle agent run

POST /sandbox/metric/metric/score-oracle

Request body

application/json, required — OracleMetricRequest

FieldTypeRequiredDescription
harbor_job_resultobject | nullnoFull Harbor job-level result.json object (oracle / reference run).
harbor_job_resultsobject[] | nullnoFull agent results array (same shape as model_response / agent_response). The oracle entry is auto-extracted by name.

Example:

{
  "harbor_job_result": {
    "stats": {
      "n_trials": 1,
      "n_errors": 0,
      "evals": {
        "default": {
          "metrics": [
            {
              "mean": 1
            }
          ],
          "reward_stats": {
            "reward": {
              "1.0": [
                "t1"
              ]
            }
          },
          "n_errors": 0
        }
      }
    }
  }
}

Responses

StatusDescriptionBody
200Oracle metric scored.OracleMetricResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—

Example response:

{
  "score": 10,
  "explanation": "Oracle mean reward 1.0 over 1 trial; no Harbor/eval errors.",
  "mean_reward": 1,
  "n_trials": 1,
  "pass_rate": 1,
  "had_error": false
}

Infer difficulty + score from oracle vs candidate

POST /sandbox/metric/metric/score-prompt-reward

Request body

application/json, required — PromptRewardRequest

FieldTypeRequiredDescription
oracle_harbor_resultobject | nullnoHarbor job result for the oracle/reference agent (typically agent_results[0].result).
candidate_harbor_resultobject | nullnoHarbor job result for the candidate agent (typically agent_results[1].result).
harbor_job_resultsobject[] | nullnoFull agent results array (same shape as model_response / agent_response). Oracle and candidate entries are auto-extracted by name.
expected_output"easy" | "medium" | "hard" | "expert" | nullnoOptional difficulty label to compare against inferred difficulty. For harbor-task-pipeline jobs, supply this on the metric request body; it is not part of the pipeline input contract.

Example:

{
  "oracle_harbor_result": {
    "stats": {
      "n_trials": 1,
      "n_errors": 0,
      "evals": {
        "default": {
          "metrics": [
            {
              "mean": 1
            }
          ],
          "reward_stats": {
            "reward": {
              "1.0": [
                "t1"
              ]
            }
          },
          "n_errors": 0
        }
      }
    }
  },
  "candidate_harbor_result": {
    "stats": {
      "n_trials": 1,
      "n_errors": 0,
      "evals": {
        "default": {
          "metrics": [
            {
              "mean": 0
            }
          ],
          "reward_stats": {
            "reward": {
              "0.0": [
                "t1"
              ]
            }
          },
          "n_errors": 0
        }
      }
    }
  },
  "expected_output": "hard"
}

Responses

StatusDescriptionBody
200Prompt reward + inferred difficulty scored.PromptRewardResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
422Request body failed Pydantic validation.—

Example response:

{
  "score": 10,
  "explanation": "Oracle mean 1.0, candidate mean 0.0; reward gap 1.0 → inferred 'hard'. Matches expected_output='hard'.",
  "difficulty": "hard",
  "difficulty_score": 1,
  "expected_output": "hard",
  "matches_expected": true,
  "oracle_mean_reward": 1,
  "candidate_mean_reward": 0
}

Score how representative the task is of real-world work

POST /sandbox/metric/metric/score-real-world-applicability

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 8,
  "explanation": "Task involves multi-file orchestration similar to real microservice deployments; only minor synthetic shortcuts.",
  "details": {
    "realism_factors": [
      "multiple cooperating containers",
      "network-bound state"
    ],
    "weak_points": [
      "tests/ never exercises a transient network failure"
    ]
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Score how well tests/ aligns with instruction.md

POST /sandbox/metric/metric/score-test-alignment

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 9,
  "explanation": "All 4 instructional requirements have at least one matching test assertion; only minor coverage gaps.",
  "details": {
    "coverage_matrix": [
      {
        "requirement": "prints integers 1..10 one per line",
        "tests": [
          "test_output_lines"
        ]
      },
      {
        "requirement": "exits 0 on success",
        "tests": [
          "test_exit_code"
        ]
      }
    ],
    "gaps": [
      "no test asserts ``\\n`` separator vs ``\\r\\n``"
    ]
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Alias of POST /metric/score-test-alignment

POST /sandbox/metric/metric/test-quality

Compatibility alias for POST /metric/score-test-alignment.

Request body

application/json, required — TaskMetricRequest

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

Example:

{
  "task_archive_url": "https://storage.example.com/tasks/exported-task.zip"
}

Responses

StatusDescriptionBody
200LLM rubric scored.LlmScoreResponse
401Missing or invalid credentials: a Keycloak bearer token, or a platform API key (SANDBOX_API_KEYS / SANDBOX_API_KEY); same auth as every Sandbox service.—
404Task bundle could not be assembled. task_slug did not match anything on disk, task_archive_url 404'd, or storage_resource was unreachable.—
422Request body failed Pydantic validation.—
502Upstream LLM or task-fetch failure — the request was well-formed but the metric service couldn't complete it. Safe to retry.—

Example response:

{
  "score": 9,
  "explanation": "All 4 instructional requirements have at least one matching test assertion; only minor coverage gaps.",
  "details": {
    "coverage_matrix": [
      {
        "requirement": "prints integers 1..10 one per line",
        "tests": [
          "test_output_lines"
        ]
      },
      {
        "requirement": "exits 0 on success",
        "tests": [
          "test_exit_code"
        ]
      }
    ],
    "gaps": [
      "no test asserts ``\\n`` separator vs ``\\r\\n``"
    ]
  },
  "task_slug": "hello-world",
  "model_used": "anthropic/claude-haiku-4-5"
}

Schemas

The object shapes referenced above.

ArtifactDownloadUrlsPayload

Optional presigned artifact URLs (same shape as RunDatapointResponse).

FieldTypeRequiredDescription
test_stdout_urlstring | nullnoPresigned GET when a single verifier stdout exists.
job_archive_urlstring | nullnoPresigned GET for zipped Harbor job directory.
test_stdout_artifactsVerifierStdoutArtifactPayload[]noPer-trial verifier stdout URLs when multiple files exist.

AverageRewardRequest

Provide either harbor_job_result (one Harbor job) or a non-empty harbor_job_results list (one result.json per agent, e.g. datapoint agent_results[].result). Both fields together, or neither, yields HTTP 422. Aliases: harbor_result, harbor_results. Request payloads use Harbor reward units (typically 0–1 per trial); the response field score is on a 1–10 scale.

FieldTypeRequiredDescription
harbor_job_resultobject | nullnoOne Harbor job-level result.json (single agent). Omit when sending harbor_job_results.
harbor_job_resultsobject[] | nullnoOne Harbor job per agent: either raw result.json (top-level stats) or a datapoint row with the job nested under result (same shape as RunDatapointResponse.agent_results[]). Score is the mean of each job's average reward, then mapped to 1–10. Do not combine with harbor_job_result.
verifier_ctrfobject | nullnoOptional CTRF test report (from verifier/ctrf.json) for the single harbor_job_result. When present, per-test pass/fail details are included in the explanation.
verifier_ctrfsobject | null[] | nullnoOptional list of CTRF reports parallel to harbor_job_results (one per agent). When present, per-test pass/fail details are included in the explanation.
artifact_download_urlsArtifactDownloadUrlsPayload | nullnoOptional presigned artifact URLs from the datapoint run; echoed in score-average-reward explanation for convenience.

AverageRewardResponse

FieldTypeRequiredDescription
scorenumberyesPrimary metric score for this endpoint.
explanationstringyesHuman-readable rationale.
mean_rewardnumber | nullnoSingle job: mean of per-trial rewards (or metrics mean). Multi job: mean of each job's average reward (unweighted across agents).
n_rewardsintegeryesSingle job: trial count (or 1 for metrics fallback). Multi job: number of agent jobs that contributed a mean_reward to the pool.
had_errorbooleanyesWhether Harbor or eval reported errors.

DeterminismRequest

Provide either a pre-assembled harbor_run_results list or agent_results + determinism_rerun_results (the first agent's main run is extracted from agent_results[0].result and prepended to the reruns).

FieldTypeRequiredDescription
harbor_run_resultsobject[] | nullnoPre-assembled list of Harbor job result.json objects (main + reruns).
agent_resultsobject[] | nullnoFull agent_results array from RunDatapointResponse. The first entry's result key is used as the main run for determinism comparison.
determinism_rerun_resultsobject[] | nullnoExtra Harbor job result.json objects from determinism reruns of the first agent (top-level field from RunDatapointResponse).

DeterminismResponse

FieldTypeRequiredDescription
scorenumberyesPrimary metric score for this endpoint.
explanationstringyesHuman-readable rationale.
run_countintegeryesNumber of Harbor results compared.
mean_rewardsnumber | null[]yesPer-run mean rewards aligned with input order.
all_means_identicalbooleanyesTrue when every run has the same mean reward.
all_means_onebooleanyesTrue when all means exist and equal 1.0.

HTTPValidationError

FieldTypeRequiredDescription
detailValidationError[]no

HarborAgentTelemetry

Normalized LLM usage for one Harbor agent invocation (possibly multi-trial).

FieldTypeRequiredDescription
modelstring | nullno
prompt_tokensinteger | nullno
completion_tokensinteger | nullno
cache_tokensinteger | nullno
total_tokensinteger | nullno
latency_msnumber | nullno
cost_usdnumber | nullno
api_callsinteger | nullno

JobCredentialsSpec

Optional per-job credential overrides keyed by provider slug.

FieldTypeRequiredDescription
anthropicProviderCredentialRef | nullno
openaiProviderCredentialRef | nullno
xaiProviderCredentialRef | nullno
googleProviderCredentialRef | nullno
fireworksProviderCredentialRef | nullno
tinkerProviderCredentialRef | nullno
githubProviderCredentialRef | nullno
llmgatewayLlmGatewayCredentialRef | nullno

JudgeArtifactUrls

Presigned S3 GET URLs for the judge Harbor job archive and verifier stdout. Present only when the artifacts bucket is configured on the worker.

FieldTypeRequiredDescription
job_archive_urlstring | nullnoPresigned URL for jobs/{job_id}/job-archive.zip (zip of the judge Harbor job tree). Expires per S3 SigV4 (max 7 days); use the agent service GET /jobs/{job_id}/artifacts/archive for a stable URL.
test_stdout_urlstring | nullnoPresigned URL for the verifier test-stdout.txt when exactly one trial produced one. None otherwise.

JudgeAsyncAcceptedResponse

202 envelope for the RFC 0005 async judge / judge-batch enqueue routes.

FieldTypeRequiredDescription
job_idstringyesWorker job id — the same value the worker uses in S3 (jobs/{job_id}/status.json and jobs/{job_id}/result.json) and the value the poll / cancel routes accept in the URL path.
request_idstringnoEcho of the inbound X-Request-ID header for log / trace correlation across the metric pod, the queue hop, and the agent worker. Default: "".
statusstringnoAlways queued on the 202 response. The async-poll endpoint reports the progression to running / succeeded / failed / cancelled. Default: "queued".
poll_urlstringyesPath of the async-poll endpoint for this job_id (e.g. /metric/judge/async/8b1f...). Pre-built so callers don't have to know the URL shape.

JudgeAsyncCancelResponse

Outcome of an async judge cancel. Always 200 on success; see was_active to distinguish first-cancel from idempotent re-cancel.

FieldTypeRequiredDescription
job_idstringyesEchoes the path parameter.
statusstringnoAlways cancelled on a 200 response. Default: "cancelled".
was_activebooleanyesTrue when the cancel flipped a non-terminal (queued / running) job to cancelled; False on an idempotent re-cancel of an already-cancelled job.

JudgeAsyncStatusResponse

Status snapshot for an async judge job. Always 200 on a successful poll; failure / cancellation surfaces in the body, not the HTTP status.

FieldTypeRequiredDescription
job_idstringyesEchoes the path parameter for client logging.
status"queued" | "running" | "succeeded" | "failed" | "cancelled"yesWorker-reported status. queued and running are non-terminal (continue polling); the other three are terminal.
updated_atstring | nullnoISO-8601 timestamp of the last status transition write, from status.json. Used by client watchdogs to detect wedged workers (RFC 0004).
heartbeat_atstring | nullnoISO-8601 timestamp of the most recent worker liveness pulse, from heartbeat.json. null when the job hasn't started running yet, when the worker predates RFC 0004, or when the heartbeat-write feature flag is off.
errorstring | nullnoWorker-side error message when status is failed or cancelled. null for non-terminal and succeeded jobs.
error_classstring | nullnoQualified Python class name of the worker exception that produced error (e.g. StorageNotFoundError). The synchronous route uses this to map worker failures to precise HTTP statuses; on the async path it is surfaced verbatim so callers can apply the same mapping themselves.
resultobject | nullnoParsed result.json envelope for the job — a JudgeMetricResponse (singleton route) or JudgeBatchResponse (batch route). Populated only when status == "succeeded"; null otherwise. Surfaced as a free-form dict because the same poll endpoint serves both job types and the per-route response model is known at the call site, not at the schema level.

JudgeBatchRequest

Batched agentic-judge request: one subject, N rubrics. Materialized once, evaluated in parallel inside one sandbox.

FieldTypeRequiredDescription
subjectJudgeBatchSubjectyesShared subject under evaluation; one source per request.
rubricsJudgeBatchRubricRequest[]yesOrdered list of rubrics. Response preserves this order. Length is capped at the route layer (metric.judgeBatchMaxRubrics).
judge_agentstring | nullnoBatch-level default agent; per-rubric overrides take precedence.
modelstring | nullnoBatch-level default model; per-rubric overrides take precedence.
timeout_secnumber | nullnoBatch-level default per-rubric timeout.
sandbox"asg" | "k8s" | "daytona" | "docker" | "prism" | nullnoPer-batch sandbox override. Same vocabulary as the singleton endpoint; the entire batch runs in one sandbox.
credential_sourcestring | nullnoOptional per-batch override of SANDBOX_METRIC_CREDENTIAL_SOURCE (registry | prism | registry_with_prism_fallback | litellm | llmgateway | registry_with_llmgateway_fallback).
gateway_workspacestring | nullnoLLM Gateway workspace slug (x-llmcp-workspace). Stamped by Prism when credential_source=llmgateway; required with gateway_project for M2M egress without a body tk_live_.
gateway_projectstring | nullnoLLM Gateway project slug (x-llmcp-project). Stamped by Prism when credential_source=llmgateway; required with gateway_workspace for M2M egress without a body tk_live_.
credentialsJobCredentialsSpec | nullnoPer-batch credential overrides (RFC 0010 §6). Inline env / api_key are never persisted to S3. Prefer omitting credentials.llmgateway.api_key and stamping gateway workspace/project for platform M2M; legacy api_key + base_url remain accepted during soak.

JudgeBatchResponse

Per-rubric results in request order plus batch-level timing.

FieldTypeRequiredDescription
resultsJudgeBatchRubricResponse[]yesPer-rubric results in request order.
subject_labelstringyesResolved label for the shared subject.
shared_setup_duration_secnumbernoWall-clock seconds spent on shared work (subject materialization, sandbox startup) before any rubric began. Default: 0.
batch_duration_secnumberyesTotal wall-clock seconds end-to-end.

JudgeBatchRubricError

Per-rubric error slot in :class:JudgeBatchResponse.

FieldTypeRequiredDescription
error_classstringyesStable string class for the failure (e.g. timeout, schema_validation, llm_error, parse_error, unknown).
messagestringnoHuman-readable failure message. Default: "".

JudgeBatchRubricRequest

One rubric inside a batched judge request.

FieldTypeRequiredDescription
labelstringyesStable, unique-within-batch identifier for this rubric.
promptstringyesFull rubric prompt for this rubric.
output_schemaobject | nullnoPer-rubric JSON Schema for the expected Judgment.details shape.
extra_contextstring | nullnoPer-rubric free-form context appended to the prompt.
judge_agentstring | nullnoPer-rubric override for the agent; falls back to batch default.
modelstring | nullnoPer-rubric override for the model; falls back to batch default.
timeout_secnumber | nullnoPer-rubric wall-clock cap; falls back to batch default.

JudgeBatchRubricResponse

One slot in :class:JudgeBatchResponse.results.

Exactly one of (score, explanation, details) and error is populated. Both being None or both being set is a server-side bug — clients should treat that as the rubric having failed with class unknown.

FieldTypeRequiredDescription
labelstringyesEchoes the request rubric's label.
scorenumber | nullno0..1 quality score on success; None on per-rubric failure.
explanationstring | nullnoHuman-readable summary on success; None on failure.
detailsobject | nullnoRubric-specific structured fields on success; None on failure.
judge_agentstringyesAgent that ran (or attempted to run) this rubric.
model_usedstringyesModel used (or attempted to be used) for this rubric.
duration_secnumberyesWall-clock seconds the rubric's LLM call consumed; 0.0 if it never started.
errorJudgeBatchRubricError | nullnoSet when the rubric failed; None on success.
telemetryHarborAgentTelemetry | nullnoLLM usage from Harbor's trial-level result.json for this rubric's judge run.

JudgeBatchSubject

Subject under evaluation for a batch. Provide exactly one source. On the platform only bundle and archive_url are accepted; manifest_url, storage_resource and task_slug return 400.

FieldTypeRequiredDescription
bundleobject | nullnoInline path → UTF-8 text map; skips remote fetch.
archive_urlstring | nullnoHTTPS URL returning either a zip archive of the subject tree OR a single file (PDF, image, document, ...). Zip payloads are extracted; single-file payloads are saved at /inputs/subject/<basename>. Alias: task_archive_url.
manifest_urlstring | nullnoLegacy CTP / GDPval _manifest.json URL. Rejected on the platform (400); send archive_url. Alias: task_manifest_url.
manifest_expires_atstring | nullnoLegacy deadline for manifest_url; only valid with it, so also unsupported on the platform.
storage_resourcestring | nullnoLegacy Drive / S3 / GCS storage location. Rejected on the platform (400); send a presigned HTTPS URL as archive_url.
storage_connector_idinteger | nullnoLegacy TI storage connector id; only valid with storage_resource, so also unsupported on the platform.
task_slugstring | nullnoLegacy local task slug. Rejected on the platform (400).

JudgeMetricRequest

Agentic judge metric: a rubric prompt + a candidate subject. The metric service dispatches a Harbor trial to the worker fleet; the inner agent (default claude-code) reads the rubric and subject and writes a Judgment JSON the verifier validates. Provide exactly one of subject_bundle or subject_archive_url (https or sandbox-object; a zip or a single file). subject_manifest_url, subject_storage_resource and subject_task_slug are rejected with 400 on the platform.

FieldTypeRequiredDescription
promptstringyesFull rubric / system prompt the judge agent receives. Written verbatim to /inputs/rubric.md inside the judge container.
rubric_labelstring | nullnoShort human-readable label surfaced in worker logs and the result envelope (e.g. "test-alignment"). Defaults to a label derived from the subject source.
output_schemaobject | nullnoOptional JSON Schema validated against the agent's judgment.json inside the verifier. When set, judgment.json MUST validate or the worker returns JudgeOutputInvalid.
extra_contextstring | nullnoOptional free-form context appended to the agent's instruction.md. Useful for dataset version, locale, etc.
subject_bundleobject | nullnoInline path → UTF-8 text map. Same shape as collect_task_bundle_from_task_dir; skips remote fetch.
subject_archive_urlstring | nullnoHTTPS URL returning either a zip archive of the subject tree OR a single file (PDF, image, document, ...). Zip payloads are extracted into /inputs/subject/ on the worker; single-file payloads are saved at /inputs/subject/<basename> so the judge agent can evaluate either shape without code changes. JSON aliases: subject_url, task_archive_url.
subject_manifest_urlstring | nullnoLegacy CTP / GDPval _manifest.json URL. Rejected on the platform (400): zip the files and send subject_archive_url. JSON aliases: manifest_url, task_manifest_url.
subject_manifest_expires_atstring | nullnoLegacy deadline for subject_manifest_url; only valid with it, so also unsupported on the platform.
subject_storage_resourcestring | nullnoLegacy Drive / S3 / GCS storage location. Rejected on the platform (400): send a presigned HTTPS URL (zip or single file) as subject_archive_url. JSON alias: storage_resource.
subject_storage_connector_idinteger | nullnoLegacy TI storage connector id; only valid with subject_storage_resource, so also unsupported on the platform. JSON alias: storage_connector_id.
subject_task_slugstring | nullnoLegacy local task slug. Rejected on the platform (400): the worker has no task tree. JSON alias: task_slug.
judge_agentstring | nullnoOverride for the Harbor agent name to run as the judge (e.g. claude-code, openhands). Defaults to the worker's configured default.
modelstring | nullnoOverride for the model id passed to the judge agent. Defaults to the worker's configured default model.
timeout_secnumber | nullnoWall-clock cap for the judge Harbor invocation. Worker may clamp this to a configured maximum.
sandbox"asg" | "k8s" | "daytona" | "docker" | "prism" | nullnoPer-request Harbor sandbox/environment override for this judge trial. Mirrors the agent service's RunDatapointRequest.sandbox so callers learn one vocabulary across both endpoints. When omitted, the worker uses its configured SANDBOX_METRIC_SANDBOX default. Values: asg is a routing hint — by the time the worker runs the trial, asg is collapsed to 'no override' (the worker is already the destination). k8s selects the K8s-Job sandbox for this trial only (cluster bits must be installed). daytona selects the Daytona SDK. docker selects the local Docker provider (needs a Docker socket on the worker host).
credential_sourcestring | nullnoOptional per-request override of SANDBOX_METRIC_CREDENTIAL_SOURCE (registry | prism | registry_with_prism_fallback | litellm | llmgateway | registry_with_llmgateway_fallback). llmgateway prefers gateway_workspace + gateway_project with platform llm_egress M2M (no body tk_live_). Legacy inline credentials.llmgateway.api_key remains accepted during soak.
gateway_workspacestring | nullnoLLM Gateway workspace slug (x-llmcp-workspace). Stamped by Prism when credential_source=llmgateway; required with gateway_project for M2M egress without a body tk_live_.
gateway_projectstring | nullnoLLM Gateway project slug (x-llmcp-project). Stamped by Prism when credential_source=llmgateway; required with gateway_workspace for M2M egress without a body tk_live_.
credentialsJobCredentialsSpec | nullnoPer-request credential overrides (RFC 0010 §6). Inline env / api_key are never persisted to S3. Prefer omitting credentials.llmgateway.api_key and stamping gateway workspace/project for platform M2M; legacy api_key + base_url remain accepted during soak.

JudgeMetricResponse

Result of an agentic judge run. The output shape is defined by the caller's output_schema: score is optional and, when present, follows whatever range the schema declares. The full judgment object is echoed in output.

FieldTypeRequiredDescription
scorenumber | nullnoOptional quality score. Presence and range are defined by the caller's output_schema; null when the judgment carries no score.
explanationstringnoHuman-readable summary of the judgment. Default: "".
detailsobjectnoRubric-specific structured fields (free-form).
outputobjectnoThe full judgment object the agent produced, verbatim. Use this when the contract is defined by output_schema rather than the score/explanation/details convention.
subject_labelstringyesResolved label for the evaluated subject (slug, archive hash, or rubric_label echo) used for logs / audit.
judge_agentstringyesHarbor agent that ran the judgment (e.g. claude-code).
model_usedstringyesModel identifier the judge agent ran with.
duration_secnumberyesWall-clock seconds the judge run consumed end-to-end.
telemetryHarborAgentTelemetry | nullnoLLM usage from Harbor's trial-level result.json for the judge agent run.
artifact_download_urlsJudgeArtifactUrls | nullnoPresigned S3 GET URLs for the judge Harbor job output (job-archive.zip + verifier stdout). Populated only when the worker has SANDBOX_METRIC_JOB_ARTIFACTS_BUCKET configured; None otherwise. The same zip is reachable long-term via the agent service GET /jobs/{job_id}/artifacts/archive keyed by the worker job_id.

LlmGatewayCredentialRef

Prism / LLM Gateway credential stamp (api_key + base_url preferred).

FieldTypeRequiredDescription
api_keystring | nullno
base_urlstring | nullno
secret_refstring | nullno
envobject | nullno

LlmScoreResponse

FieldTypeRequiredDescription
scorenumberyesPrimary metric score for this endpoint.
explanationstringyesHuman-readable rationale.
detailsobjectnoStructured fields returned by the LLM judge.
task_slugstringyesTask label used for this evaluation.
model_usedstringyesResolved LLM model id used for the judge call.

ModelBreakingRequest

FieldTypeRequiredDescription
harbor_job_resultobject | nullnoFull Harbor job-level result.json object (candidate / model-under-test run).
harbor_job_resultsobject[] | nullnoFull agent results array (same shape as model_response / agent_response). The candidate entry is auto-extracted by name.

ModelBreakingResponse

FieldTypeRequiredDescription
scorenumberyesPrimary metric score for this endpoint.
explanationstringyesHuman-readable rationale.
pass_ratenumber | nullno
n_trialsintegeryesTrial count from Harbor summary.
n_success_trialsintegeryesTrials counted as success for pass-rate fallback.
thresholdnumbernoInternal threshold reference (model-breaking scoring). Default: 0.05.
had_errorbooleanyesWhether Harbor or eval reported errors.
below_thresholdbooleanyesTrue when candidate accuracy (mean_reward or pass_rate) is at or below the 5% failure-guarantee threshold.

OracleMetricRequest

FieldTypeRequiredDescription
harbor_job_resultobject | nullnoFull Harbor job-level result.json object (oracle / reference run).
harbor_job_resultsobject[] | nullnoFull agent results array (same shape as model_response / agent_response). The oracle entry is auto-extracted by name.

OracleMetricResponse

FieldTypeRequiredDescription
scorenumberyesPrimary metric score for this endpoint.
explanationstringyesHuman-readable rationale.
mean_rewardnumber | nullnoMean reward from Harbor eval stats, if present.
n_trialsintegeryesTrial count from Harbor summary.
pass_ratenumber | nullnoPass rate proxy when mean reward is missing.
had_errorbooleanyesWhether Harbor or eval reported errors.

PromptRewardRequest

Provide either oracle_harbor_result + candidate_harbor_result (individual dicts) or a harbor_job_results array (full agent_response / model_response); oracle and candidate are auto-extracted by name. Supply expected_output here directly when comparing against a known difficulty label; the harbor-task-pipeline request no longer carries that label.

FieldTypeRequiredDescription
oracle_harbor_resultobject | nullnoHarbor job result for the oracle/reference agent (typically agent_results[0].result).
candidate_harbor_resultobject | nullnoHarbor job result for the candidate agent (typically agent_results[1].result).
harbor_job_resultsobject[] | nullnoFull agent results array (same shape as model_response / agent_response). Oracle and candidate entries are auto-extracted by name.
expected_output"easy" | "medium" | "hard" | "expert" | nullnoOptional difficulty label to compare against inferred difficulty. For harbor-task-pipeline jobs, supply this on the metric request body; it is not part of the pipeline input contract.

PromptRewardResponse

FieldTypeRequiredDescription
scorenumberyesPrimary metric score for this endpoint.
explanationstringyesHuman-readable rationale.
difficulty"easy" | "medium" | "hard" | "expert" | nullnoInferred difficulty from reward gap.
difficulty_scorenumber | nullnoNumeric mapping of difficulty tier.
expected_output"easy" | "medium" | "hard" | "expert" | nullnoExpected label from request, if any.
matches_expectedboolean | nullnoWhether inferred difficulty equals expected_output when both are set.
oracle_mean_rewardnumber | nullnoMean reward from oracle Harbor result.
candidate_mean_rewardnumber | nullnoMean reward from candidate Harbor result.
oracle_errorstring | nullnoError detail when oracle run had Harbor/eval issues.
candidate_errorstring | nullnoError detail when candidate run had issues.

ProviderCredentialRef

One provider's credential source on a job request.

FieldTypeRequiredDescription
secret_refstring | nullno
envobject | nullno

ScoreOnlyResponse

FieldTypeRequiredDescription
scorenumberyesPrimary metric score for this endpoint.
explanationstringyesHuman-readable rationale.

TaskMetricRequest

Task rubric (LLM) and static metrics: provide one of: inline task_bundle; task_archive_url (HTTPS zip); or a task_slug under SANDBOX_METRIC_TASKS_ROOT (empty unless tasks are mounted). Google Drive / TI sources (storage_resource, storage_connector_id) are rejected on the platform. task_slug is optional with a URL. Optional model and extra_context apply to LLM judge routes.

FieldTypeRequiredDescription
task_slugstringnoTask directory under SANDBOX_METRIC_TASKS_ROOT. Optional when task_bundle or task_archive_url is provided; then used as the cache key and display label. Default: "".
task_bundleobject | nullnoInline path→text map (same shape as collect_task_bundle); skips disk lookup.
modelstring | nullnoLLM judge model id; defaults to METRIC_JUDGE_MODEL when omitted.
extra_contextstring | nullnoOptional extra text passed to the judge.
storage_resourcestring | nullnoLegacy Google Drive / TI location. Rejected on the platform (400): send task_archive_url or task_bundle instead.
storage_connector_idinteger | nullnoLegacy TI storage connector id. Ignored on the platform; Drive / TI sources are not fetched — send task_archive_url or task_bundle.
task_archive_urlstring | nullnoHTTPS URL to a task zip. JSON alias: task_url.

ValidationError

FieldTypeRequiredDescription
locstring | integer[]yes
msgstringyes
typestringyes
inputanyno
ctxobjectno

VerifierStdoutArtifactPayload

Matches agent API VerifierStdoutArtifactItem.

FieldTypeRequiredDescription
relative_pathstringyes
urlstring | nullno

Machine-readable spec: OpenAPI YAML.

On this page

Common headersEndpointsRun an agentic judge over an arbitrary subject directory.Request bodyResponsesRun an agentic judge over an arbitrary subject directory for N rubrics in parallel.Request bodyResponsesEnqueue a batched agentic judge job and return immediately.Request bodyResponsesEnqueue an agentic judge job and return immediately.Request bodyResponsesPoll an async judge job for status / result.ParametersResponsesCancel an in-flight async judge job.ParametersResponsesAlias of POST /metric/score-prompt-rewardRequest bodyResponsesAverage reward → 1–10 scoreRequest bodyResponsesScore whether tests check behavior vs implementation detailsRequest bodyResponsesScore determinism across rerunsRequest bodyResponsesScore completeness of instruction.md documentationRequest bodyResponsesScore the fraction of tests that target edge casesRequest bodyResponsesScore risk that a correct implementation fails the testsRequest bodyResponsesScore risk that a wrong implementation passes the testsRequest bodyResponsesStatic heuristic for instruction/tests leakageRequest bodyResponsesScore candidate as model-breakingRequest bodyResponsesScore the oracle agent runRequest bodyResponsesInfer difficulty + score from oracle vs candidateRequest bodyResponsesScore how representative the task is of real-world workRequest bodyResponsesScore how well tests/ aligns with instruction.mdRequest bodyResponsesAlias of POST /metric/score-test-alignmentRequest bodyResponsesSchemasArtifactDownloadUrlsPayloadAverageRewardRequestAverageRewardResponseDeterminismRequestDeterminismResponseHTTPValidationErrorHarborAgentTelemetryJobCredentialsSpecJudgeArtifactUrlsJudgeAsyncAcceptedResponseJudgeAsyncCancelResponseJudgeAsyncStatusResponseJudgeBatchRequestJudgeBatchResponseJudgeBatchRubricErrorJudgeBatchRubricRequestJudgeBatchRubricResponseJudgeBatchSubjectJudgeMetricRequestJudgeMetricResponseLlmGatewayCredentialRefLlmScoreResponseModelBreakingRequestModelBreakingResponseOracleMetricRequestOracleMetricResponsePromptRewardRequestPromptRewardResponseProviderCredentialRefScoreOnlyResponseTaskMetricRequestValidationErrorVerifierStdoutArtifactPayload