# Diagnose a failed job or run (/api/why)

`GET /api/why`

Classifies why a CI job failed (sling why) — step_failure / timeout / cancelled / terminated / oom / infra / network_egress / hang / unknown — with evidence, suggested actions, and a downstream-agent prompt, read deterministically from the CI facts store. No LLM in the request path.

Base URL: `https://runners.starsling.dev`

## Authentication

Requires a bearer token (`Authorization: Bearer`).

## Parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `org` | query | string | yes | GitHub organization login. Scopes the request to your membership. e.g. `acme` |
| `job_id` | query | string | no | Diagnose this job. Give either job_id or run_id, not both. e.g. `88886665361` |
| `run_id` | query | string | no | Diagnose this run — the most diagnosable failed job in it is chosen. e.g. `2990884649` |

## Responses

| Status | Description |
| --- | --- |
| `200` | A deterministic read of why the job failed: a classification, the evidence behind it, and what to try next. |
| `400` | Neither `job_id` nor `run_id` was given, or both were — a diagnosis targets exactly one. |
| `401` | No credential, or a GitHub grant too old to read org membership — re-run `sling login`. |
| `403` | You are not a member of the org named in `?org=`. |
| `404` | No such job or run in that org, or the run has no diagnosable failed job. A target in an org you can't see answers the same way. |
| `422` | `job_id` or `run_id` is not a positive decimal id. `details` names the offending field. |
| `500` | The control plane failed, or the CI facts store is not configured for this deployment. |

### `200` body

- `job_id` — string, required
- `job_name` — string, required
- `conclusion` — string, required
- `classification` — string, required. `step_failure`, `hang`, `oom`, `timeout`, `cancelled`, `infra`, `terminated`, `network_egress`, `unknown`
- `summary` — string, required
- `evidence` — array<object>, required
  - array of object
    - `kind` — string, required
    - `ref` — string, required
- `logs` — string, required
- `log_window` — string, required
- `suggested_actions` — array<object>, required
  - array of object
    - `title` — string, required
    - `command` — string, required
- `prompt` — string, required
- `meta` — object, required
  - `truncated` — boolean, required

### Example

```json
{
  "job_id": "88886665361",
  "job_name": "typecheck",
  "conclusion": "failure",
  "classification": "step_failure",
  "summary": "Step `Run bun run typecheck` failed with exit code 2.",
  "evidence": [
    {
      "kind": "step",
      "ref": "Run bun run typecheck"
    },
    {
      "kind": "log_line",
      "ref": "812"
    }
  ],
  "logs": "##[error]Process completed with exit code 2.",
  "log_window": "src/index.ts(42,7): error TS2322: Type 'string' is not assignable to type 'number'.",
  "suggested_actions": [
    {
      "title": "Read the failing step's log",
      "command": "sling logs att_88886665361.1"
    }
  ],
  "prompt": "The job `typecheck` failed at step `Run bun run typecheck` with a TS2322 type error in src/index.ts:42.",
  "meta": {
    "truncated": false
  }
}
```