Installing the CLI¶
Prerequisites¶
- Python 3.13+
- uv for Python package management
- Access to a Hawk deployment (API server URL + OAuth2 credentials)
(Node.js 22, pnpm, and Graphviz are only needed for developing Hawk itself, not for using the CLI — see Contributing.)
Install the CLI¶
Install from PyPI with uv (or pip):
To match a specific Hawk deployment, pin the release: uv tool install "hawk[cli]==2.0.0"
(run hawk version, or check <API_URL>/version, to see which version the server runs).
PyPI installs pull upstream Inspect AI
The published package depends on the upstream inspect-ai and inspect-scout
PyPI releases. METR-operated deployments pin lightly-patched forks via
[tool.uv.sources], which don't ship in package metadata — so a hawk local
run from a PyPI install builds its runner venv with upstream Inspect, not
the fork. This is expected and fine for normal use; cluster runs (which use the
deployment's runner image) are unaffected. To match a deployment's exact
Inspect build, install from source instead (below).
Install from source (dev)
To hack on the CLI or run the latest unreleased main:
Configuration¶
Set these environment variables before using the CLI, or put them in a .env file:
| Variable | Required | Description |
|---|---|---|
HAWK_API_URL |
Yes | URL of your Hawk API server |
HAWK_LOG_VIEWER_URL |
No | URL for the web log viewer (overrides what the API advertises) |
HAWK_MIDDLEMAN_URL |
No | URL of the Middleman LLM proxy, used by hawk models (overrides what the API advertises) |
HAWK_RELAY_URL |
No | URL of the relay used by hawk acp / hawk attach (overrides what the API advertises) |
HAWK_AI_GATEWAY_URL |
No | LLM gateway URL for hawk local runs (local-only; not advertised by the API) |
HAWK_ACCESS_TOKEN |
No | Bearer token to use instead of hawk login — for CI and other non-interactive use |
HAWK_DATADOG_EVAL_SET_DASHBOARD_URL |
No | Datadog dashboard URL for eval sets |
HAWK_DATADOG_SCAN_DASHBOARD_URL |
No | Datadog dashboard URL for scans |
HAWK_RUNNER_LOG_FORMAT |
No | Set to json for structured runner logs (useful with hawk local) |
HAWK_VERSION_CHECK |
No | What to do when the CLI and server versions differ: prompt (default — warn and ask to continue), warn (warn only), block (abort), or off |
OIDC configuration is discovered automatically from the API server — no OIDC env vars are needed for the CLI.
Each variable resolves independently — pin all URLs to one deployment
The CLI reads each variable separately from the environment, the current directory's .env, and the global ~/.config/hawk-cli/env; an explicit URL in the global file overrides auto-discovery.
Symptom: with a stale global config, API calls hit the new deployment while hawk models/hawk web silently talk to an old one — typically a cryptic invalid_issuer 401.
Fix: always set HAWK_API_URL, HAWK_MIDDLEMAN_URL, and HAWK_LOG_VIEWER_URL together for the same deployment — scripts/dev/generate-env.py emits all three.
INSPECT_LOG_ROOT_DIR
This is an Inspect-level variable used by the runner inside the cluster, not the CLI. Set it on the cluster (via Pulumi) or in your local environment only if you're running hawk local and want to override where .eval files are written.
Version compatibility¶
Hawk uses SemVer (e.g. 2.0.0). Before each command the CLI probes the API's
GET /version and warns when the two have drifted out of sync — the common cause
of a command that works for one person but not another. A differing major
version means a backwards-incompatible change and is flagged as likely
incompatible; same-major drift is compatible per SemVer. The API and middleman
each expose GET /version and an X-Hawk-Server-Version response header; the
drift check uses the API's (the deployment's version).
To pin the CLI to a deployment, install the matching release (e.g.
uv tool install "hawk[cli]==2.0.0"; see Install the CLI).
HAWK_VERSION_CHECK controls the reaction to drift:
prompt(default) — warn and ask to continue. Non-interactively (CI, scripts) there's no prompt, so it warns and proceeds — same aswarn.warn— warn and proceed.block— abort on any drift (including SemVer-compatible patch/minor). Recommended for CI when you need an exact match.off— skip the check.
Authentication¶
This authenticates via the browser-based PKCE flow (a localhost callback on port 18922). OIDC configuration is fetched from the API server and cached locally. Running hawk login also refreshes the cached OIDC configuration.
On headless machines (SSH boxes, containers), use hawk login --no-browser. You don't need to know which OIDC provider your deployment uses — the CLI picks the best flow it supports:
- Provider implements the device grant (Okta, Auth0, most enterprise IdPs) → the OAuth2 Device Authorization flow. Prints a short user code and a URL; approve it in a browser on any device and the CLI picks up the result on its own. Nothing to copy back.
- Provider doesn't (the default Cognito auth — user pools have no device-authorization endpoint) → paste-back PKCE. Prints a login URL to open on any device, then you paste the resulting
http://localhost:18922/callback?...redirect URL (which fails to load in your browser — that's expected) back into the CLI.
In the paste-back case, if you SSH with -L 18922:localhost:18922 the login completes automatically without pasting. You can also feed the URL in from a file: hawk login --no-browser < url.txt.
hawk login --device forces the device flow rather than letting the CLI choose, and fails with "device flow not supported by the current OIDC provider" if the provider lacks it — useful when you want a script to assert the flow instead of silently falling back.
For fully non-interactive use (CI, service accounts), set HAWK_ACCESS_TOKEN to a valid bearer token — the CLI uses it directly and skips hawk login.
Run your first eval¶
The example configs live in the repo, so this needs the cloned repo (paths are relative to the repo root):