# Jog's advice API

Jog measures what every job uses on its machine: its CPU at each eighth of its CPUs, its memory and its work disk. The advice API turns that into each job's right size. The Jog skill (https://usejog.com/skills/jog/SKILL.md) uses it; so can anything else. Every answer is JSON.

## Tokens

Calls take a Jog personal access token: `Authorization: Bearer jog_pat_…`. A token acts for one person and reads advice only, of their accounts. It reads nothing else on Jog: no money, settings, logs or other pages. Advice is for an account's owners for now.

- **For an agent**: `POST https://usejog.com/api/device` with `{"name", "access": "advice", "org"}` (`org`, an account's login, is optional: without it the token reads all the person's accounts). The person approves the code in their browser; poll `POST /api/device/token` with `{"deviceCode"}` every `interval` seconds until it answers `key`. It lasts 7 days.
- **For CI**: the person makes one at https://usejog.com/account/-/tokens, for all their accounts or one, for 7, 30 or 90 days. It is shown once.

Revoke a token there, or with `POST https://usejog.com/api/key/revoke` and the token itself. Jog keeps only a token's hash. Its text is `jog_pat_`, 64 hex digits and 8 of check: the first 4 bytes of the SHA-256 of the rest.

## GET /api/orgs/{org}/advice

Every job's advice over the last 30 days. Query: `goal` (`cost`, `balanced` or `speed`; the account's own otherwise, `balanced` until it chooses) and `until` (the window's end, at most now).

- `goal`, `now`, `window` (`start`, `end`).
- `jobs`: one each, the changes to make first.
  - `kind`: today `smaller`, `larger`, `more-memory`, `worked`, `go-back`, `few` or `right`. Read it as text: a kind added later comes with its own `title` and `detail`.
  - `title`, `detail`: the advice in words, with its figures.
  - `job`: `repo` (`owner/name`), `repoId`, `workflow`, `workflowFile`, `name` (GitHub's job name; a matrix leg's has its values).
  - `size`: its runner now. `to`: the runner to move to, or null.
  - `now`: its runs on `size`: `runs` counted, `ran`, `passed`, `failed`, `pace`, `medianSeconds`, `cost` (micro-dollars over the window, at the price each run was charged).
  - `after`: what `to` would make of the same runs: `medianSeconds` (for a bigger size, its best case), `cost`, `costMost`.
  - `before`: for `worked` and `go-back`, the size before the move, its runs as `now` has them, and `since`.
  - `loadUsec`: time at each eighth of its CPUs, least first. `memoryPeakBytes`, `memoryP95Bytes`, `diskPeakBytes`, and `limits` (`to`'s memory and disk).
  - `killed`: runs killed for memory. `unmeasured`: passing runs Jog couldn't use.

## GET /api/orgs/{org}/advice/runs

Every run in the window, or one job's (`repoId`, `workflowFile` and `job` together), newest first, 1,000 a page. The next page: `beforeAt` and `beforeJobId` from `next`. Take the same `until` as the advice to read the same window. Each run: `jobId`, `job`, `at`, `size`, `seconds`, `cost`, `counted` (`counted`, `not_passed`, `unmeasured`), `outcome` (`passed`, `failed`, `neither`), `loadUsec`, `cpuUsec`, `cpuPeakMillicpus`, `memoryPeakBytes`, `diskPeakBytes`, `ioReadBytes`, `ioWriteBytes`, `networkRxBytes`, `networkTxBytes`, `memoryKills`. A job's `passed` and `failed` are counts of its runs' outcomes.

## Errors

`{"error": code, "message": words}`: 400 `bad_request`; 401 `bad_key` (ended, revoked or malformed); 403 `key_not_allowed` (a route a token can't call), `not_owner`; 404 `not_found` (an account the token doesn't reach is not found, as a stranger's is); 503 `busy` (ask again in a few seconds).

How each verdict is made is in Jog's design notes: each figure is worked out by Jog, so the same runs always give the same advice under a goal.
