CLI (mrl)

mrl is the ModelRelay command-line client. Use it to make model requests, sign in and create API keys, and manage customers, tiers, and usage.

Quick start

brew install tensor-systems/tap/mrl

mrl auth login --web                         # or --device on a machine without a browser
mrl keys create --name laptop                # creates a key and saves it to the profile
mrl config set --model claude-sonnet-5-5     # default model

mrl "What is the capital of France?"

Installation

Homebrew (macOS/Linux)

brew install tensor-systems/tap/mrl

To upgrade:

brew upgrade mrl

Manual download

Download a release for macOS or Linux (arm64 or amd64) from releases.modelrelay.ai/mrl and add it to your PATH.

Check the installed version with mrl version or mrl --version.

Sign in and create API keys

Most commands use a secret API key (mr_sk_*). Creating keys and tiers uses an account token instead, which mrl auth login stores in the active profile.

mrl auth login --web                          # browser OAuth on this machine (GitHub by default)
mrl auth login --web --provider google        # browser OAuth with Google
mrl auth login --device                       # approve a link from any device
mrl auth logout                               # clear the stored account token

Password accounts can log in with --email and --password-stdin:

printf '%s' "$PASS" | mrl auth login --email you@example.com --password-stdin

An expired login is refreshed automatically. If refreshing fails, run mrl auth login again.

Device sign-in

--web needs a browser on the machine running mrl. On a server, or a machine an agent drives while you are away from it, use device sign-in:

mrl auth login --device

The first line of stdout is the link and code to relay:

Open https://modelrelay.ai/device?code=WDJB-MJHT and approve code WDJB-MJHT

Open the link on any device, sign in with GitHub or Google (or create an account; new accounts get the signup credit), and tap Approve. The code is already filled in. mrl waits, saves the account token, and exits. The code expires after 10 minutes.

For agents, --json prints one JSON line before waiting and one after:

mrl auth login --device --json
# {"expires_in":600,"interval":5,"status":"pending","user_code":"WDJB-MJHT","verification_uri":"https://modelrelay.ai/device","verification_uri_complete":"https://modelrelay.ai/device?code=WDJB-MJHT"}
# {"profile":"default","status":"logged_in"}

Device sign-in uses the OAuth 2.0 Device Authorization Grant (RFC 8628); see Device sign-in for the endpoints.

API keys

# Create a key, print it once, and save it as the active profile's api_key
mrl keys create --name laptop

# Print only the secret (newline-terminated) and save nothing, for scripts
KEY=$(mrl keys create --name my-app --print)

# A key with a hard lifetime spend limit, in cents ($5.00 here)
KEY=$(mrl keys create --name app-review --spend-limit 500 --print)

# List keys (redacted), with each limited key's spend so far
mrl keys list

# Revoke a key by its ID (from `mrl keys list`)
mrl keys revoke 3f2a...
Flag Description
--name Label for the key (required)
--print Print only the secret to stdout; do not save it to the profile
--spend-limit Hard lifetime spend limit in cents

A spend-limited key is refused with 402 API_KEY_SPEND_LIMIT_REACHED on every billable endpoint once its settled spend reaches the limit. The check runs before each request, so requests already in flight when the limit is reached can take spend slightly past it. The limit cannot be raised: revoke the key and create another. A spend-limited key cannot mint customer tokens.

The key is created in --project (or MODELRELAY_PROJECT_ID / the profile’s project_id); otherwise in your account’s default project. If the account has several projects and no default, mrl lists them and asks for --project.

Configuration

Environment variables

export MODELRELAY_API_KEY=mr_sk_...         # secret API key (MODELRELAY_SECRET_KEY also works)
export MODELRELAY_TOKEN=...                 # account token (overrides the stored login)
export MODELRELAY_PROJECT_ID=...            # project UUID
export MODELRELAY_API_BASE_URL=...          # defaults to https://api.modelrelay.ai/api/v1
export MODELRELAY_MODEL=claude-sonnet-5-5   # default model

Flags override environment variables, which override the config file.

Config file

~/.config/mrl/config.toml (or $XDG_CONFIG_HOME/mrl/config.toml):

current_profile = "default"

[profiles.default]
api_key = "mr_sk_..."
base_url = "https://api.modelrelay.ai/api/v1"
project_id = "<uuid>"
model = "claude-sonnet-5-5"
output = "table"  # or "json"

# Defaults for `mrl do`
allow_all = false
allow = ["git ", "npm "]
trace = true

mrl auth login and mrl keys create write token and api_key into the active profile for you.

Profiles

mrl config set --profile dev --api-key mr_sk_... --model claude-sonnet-5-5
mrl config use dev        # make dev the current profile
mrl config show           # show the current profile
mrl --profile dev "Hi"    # use a profile for one command

mrl config set accepts --profile, --api-key, --base-url, --project, --model, --output (json or table), and the mrl do defaults --allow-all, --allow, and --trace.

Make a request

Pass a prompt to send it to a model through the Responses API:

mrl "What is 2 + 2?"
mrl "Write a haiku" --stream
mrl "Explain recursion" --model claude-sonnet-5-5 --usage

A model is required: pass --model, set MODELRELAY_MODEL, or run mrl config set --model.

Piped text is prepended to the prompt:

git diff | mrl "Explain these changes"
cat README.md | mrl "Summarize this"

Attach files with -a:

mrl "Describe this screenshot" -a ./screenshot.png
Flag Description
--model Model ID (overrides the profile default)
--system System prompt
--stream Stream output as it is generated
--usage Show token usage after the response
-a, --attachment Attach a local file; repeatable; - reads stdin
--attachment-type Override the attachment MIME type (useful for stdin)
--attach-stdin Attach piped stdin as a file instead of prepending it as text

Quick tasks with do

mrl do runs a local tool loop: the model can run shell commands on your machine to complete a task.

mrl do "show git status" --allow "git "
mrl do "run tests and fix any failures" --allow-all

No commands are allowed by default. Use --allow to permit command prefixes, or --allow-all to permit any command. Set defaults with mrl config set --allow "git " --trace.

The loop calls the Responses API, executes the returned tool calls locally, sends the results back, and stops when the model replies without tool calls. Tool execution happens only on your machine.

sequenceDiagram
    participant CLI as mrl CLI
    participant API as /responses API
    participant Local as Local Shell

    CLI->>API: POST /responses [system, user]
    API-->>CLI: tool_call: bash "git status"
    CLI->>Local: git status
    Local-->>CLI: output
    CLI->>API: POST /responses [... + tool_result]
    API-->>CLI: text, no tool calls
    Note over CLI: No tool calls → exit loop
Flag Description
--model Model ID (overrides the profile default)
--system System prompt
--allow Allow a bash command prefix; repeatable
--allow-all Allow all bash commands
--max-turns Maximum tool loop turns (default 50)
--trace Print tool calls as they execute

Models

# List text-generation models in the catalog
mrl model list

# Filter by provider and capability
mrl model list --provider openai --capability text_generation

# Include deprecated models
mrl model list --include-deprecated --json

--capability defaults to text_generation.

Resolve a route

Inspect the concrete model, selected provider, and pricing provenance for a Responses request without making a model call:

mrl response resolve --model claude-sonnet-5-5 --json

--model is required; --provider pins a provider. The command creates no usage or settlement record.

Customers, tiers, and usage

Customers

mrl customer list
mrl customer get <customer-id>
mrl customer create --external-id user_123 --email user@example.com

Tiers

mrl tier list
mrl tier get <tier-id>

mrl tier create uses an account token (run mrl auth login first) and needs a project:

# A $10/month Pro subscription billed through Stripe
mrl tier create --code pro --name "Pro" --billing-mode subscription \
  --provider stripe --price 1000 --interval month \
  --model grok-4.7 --default-model grok-4.7

# A pay-as-you-go tier seeded with $1 of promo credit
mrl tier create --code paygo --name "Pay as you go" --billing-mode paygo \
  --promo-credits 100 --model grok-4.7 --default-model grok-4.7
Flag Description
--code Tier code (required)
--name Display name
--billing-mode subscription or paygo (required)
--provider Billing provider for subscription tiers, such as stripe
--price Subscription price in cents
--interval month or year
--trial-days Free-trial length in days
--promo-credits Promo credit granted on a customer’s first token, in cents
--spend-limit Spend ceiling in cents for subscription tiers; omit for none, 0 permits no spend
--model Model available on the tier; repeatable
--default-model Which --model is the default
--token-ttl Maximum customer-token TTL in seconds

See Tiers and margins for how tiers price and limit usage.

Usage

mrl usage account

JSON schema lint

Check a JSON schema for provider compatibility before using it for structured output or tool parameters:

mrl schema lint ./schema.json
mrl schema lint ./schema.json --provider openai
mrl schema lint ./tool-schema.json --provider openai --tool-schema
cat schema.json | mrl schema lint -

--provider accepts openai, anthropic, googleai, or xai. --tool-schema validates the schema as tool parameters (OpenAI only).

Output formats

Table output is the default. Use --json for machine-readable output, or set output = "json" in the profile:

mrl customer list --json
mrl model list --json

Global flags

These flags work with every command:

Flag Description
--profile Config profile
--api-key Secret API key (mr_sk_*)
--token Account token (from mrl auth login)
--project Project UUID
--base-url API base URL
--json Output JSON
--timeout Request timeout (default 30s)

Next steps