Getting Started¶
This guide covers the CLI/server install. If you prefer a GUI, the desktop app (macOS, Windows, Linux) wraps the same relay with a system tray, dashboard, and one-click sign-in — see the README's install section for its one-line installers and desktop/README.md.
Install¶
One line on macOS or Linux, without sudo:
curl -fsSL https://raw.githubusercontent.com/lpalbou/AIRelays/main/scripts/install-headless.sh | bash
The script installs the newest PyPI release into an isolated environment
(uv tool or a Python 3.11+ virtualenv) and links ~/.local/bin/airelays.
Set AIRELAYS_VERSION=X.Y.Z to pin a release; run it again to upgrade.
From PyPI directly:
python -m pip install airelays
From a source checkout:
python -m pip install .
Initialize AIRelays¶
airelays init
This prepares:
- config:
~/.config/airelays/config.toml - data dir:
~/.airelays - logs dir:
~/.airelays/logs - relay token:
~/.airelays/relay-token
Show the current relay token at any time:
airelays token show
Custom Configuration¶
The CLI and desktop use the same saved accounts and relay configuration by
default. To use another configuration, pass --config consistently when
signing in, inspecting accounts, and starting the relay:
airelays --config ./relay.toml init
airelays --config ./relay.toml claude login
airelays --config ./relay.toml claude accounts --json
airelays --config ./relay.toml serve --host 127.0.0.1 --port 8080
Shared options such as --config and --data-dir work before or after
subcommands. A later explicit value takes precedence. See
Configuration for paths and environment overrides.
OpenAI Runtime¶
Log in:
airelays login
On a server or over SSH (no local browser), use device-code login — you approve the sign-in from a browser on any other device:
airelays login --device
airelays login selects the device flow automatically on SSH sessions and
displayless Linux. The browser flow's URL only works in a browser on the
same machine as the relay (its redirect targets localhost:1455 there).
You can enroll several of your own OpenAI accounts: running airelays login
again with a different account adds it alongside the first, and the relay
balances across them (see the README's "Multiple OpenAI Accounts" section).
Sign an account out with airelays logout <email>; manage order and
capacity holds with airelays accounts.
Start the server:
airelays doctor
airelays serve --host 127.0.0.1 --port 8080
Verify:
curl http://127.0.0.1:8080/v1/models \
-H 'authorization: Bearer YOUR_AIRELAYS_TOKEN'
curl http://127.0.0.1:8080/v1/chat/completions \
-H 'authorization: Bearer YOUR_AIRELAYS_TOKEN' \
-H 'content-type: application/json' \
-d '{
"model": "gpt-5.5",
"messages": [{"role": "user", "content": "Reply with exactly: OPENAI AIRelays OK"}]
}'
OpenAI Open Local Relay Mode¶
airelays init --no-auth
airelays login
airelays serve --no-auth --host 127.0.0.1 --port 8080
In this mode AIRelays does not require Authorization on /v1/*. Open local relay mode applies to all enabled providers, including the Claude runtime.
Claude Runtime¶
AIRelays uses only Claude accounts it owns. Add one with a browser sign-in:
airelays claude login
airelays claude login # optional: add another of your own accounts
airelays claude accounts
Each sign-in creates a separate Claude Code profile under
~/.airelays/claude/accounts/<id>/. Claude Code owns its credentials and
refreshes them. The desktop offers Sign in / Add account →
"In a browser" in the Anthropic card. Usage bars need a Claude Code version
that supports get_usage (verified with 2.1.292+); requests work without it.
Headless Claude login — claude setup-token needs a browser, so run it on
any machine that has one, then carry the token to the server:
# on a machine with a browser:
claude setup-token
# on the server:
airelays init
airelays claude set-token # paste the token; stored 0600, survives restarts
The token is stored in ~/.airelays/claude-token and appears as the account
default (desktop: "With a token"). It is inference-only: Claude reports no
usage or email for setup tokens, so it has no usage bar and cannot be
deduplicated against browser accounts.
Your personal Claude Code sign-in (~/.claude), an inherited
CLAUDE_CONFIG_DIR, and an exported CLAUDE_CODE_OAUTH_TOKEN are never
used; airelays doctor reports an ignored CLAUDE_CODE_OAUTH_TOKEN. Until an
account is connected, claude:* requests return 503 provider_auth_error.
Manage one account using its email or id from airelays claude accounts:
airelays claude login --replace ACCOUNT
airelays claude logout ACCOUNT
Renewal requires the same account and pauses that profile until sign-in
succeeds. To renew the setup token, run airelays claude set-token again.
Duplicate browser subscriptions receive only one share of traffic.
Signing out runs claude auth logout inside that AIRelays profile only;
airelays claude logout default only deletes the stored setup token. Neither
touches your personal Claude Code sign-in. Use --all only to sign out all
AIRelays accounts. The running relay discovers account changes automatically
and balances requests across eligible accounts with capacity.
Start AIRelays with the Claude runtime enabled:
airelays serve --host 127.0.0.1 --port 8080
Verify:
curl http://127.0.0.1:8080/v1/chat/completions \
-H 'authorization: Bearer YOUR_AIRELAYS_TOKEN' \
-H 'content-type: application/json' \
-d '{
"model": "claude:sonnet",
"messages": [{"role": "user", "content": "Reply with exactly: CLAUDE AIRelays OK"}]
}'
Current Claude limits:
- runs through the
claudeCLI on the relay's machine - served on the relay's listener, local or network
- follows the relay's protected or open local authentication mode
- no audio, no image generation (GPT models only), no server-side tools (web search), no forced tool calls
Status¶
Inspect relay and provider readiness:
airelays status
Usage windows of the running relay, including the image-generation quota:
airelays usage
Image Generation¶
GPT models also generate and edit images through OpenAI's Images routes:
curl http://127.0.0.1:8080/v1/images/generations \
-H 'authorization: Bearer YOUR_AIRELAYS_TOKEN' \
-H 'content-type: application/json' \
-d '{"prompt": "a watercolor fox", "quality": "low"}'
The image comes back as PNG b64_json; /v1/images/edits takes the image
to change as a multipart file. See
API Notes.
Run local setup checks plus live upstream probes:
airelays doctor
airelays doctor checks config, relay-token state, OpenAI login readiness,
upstream /models, a tiny /responses smoke request, and Claude readiness
when the Claude runtime is enabled. Use airelays doctor --skip-response
to skip the response smoke request.
List every model id the running relay accepts, grouped by provider, with each model's reasoning modes and, when the provider publishes one, its API list price per 1M tokens (a relative cost indicator; subscription requests are not billed per token):
airelays models
Machine-readable output:
airelays status --json
airelays doctor --json
airelays models --json
airelays status shows:
- the installed AIRelays version (title line)
- relay config and token state
- Who can connect: the enforced network scope
- OpenAI runtime readiness
- Claude runtime readiness when enabled
- next recommended commands
Provider Routing¶
- models starting with
claude:use the Claude runtime when it is enabled - other model ids use the OpenAI runtime when it is enabled
- AIRelays rejects requests when the selected runtime is disabled or the route is outside that runtime's published subset
Client Configuration¶
Base URL:
http://127.0.0.1:8080/v1
Standard OpenAI SDKs can use the AIRelays relay token through their normal api_key field when the base_url points at AIRelays.
Example shell setup:
export OPENAI_BASE_URL='http://127.0.0.1:8080/v1'
export AIRELAYS_TOKEN="$(tr -d '\n' < ~/.airelays/relay-token)"
Use The Relay From Other Devices¶
airelays serve listens on 127.0.0.1 by default, so only this machine can
connect. To serve your phone, another computer, or a Tailscale network,
listen on all interfaces:
airelays serve --host 0.0.0.0 --port 8080
The default network_scope = "private" then admits this machine and private
networks (home and office LANs, 100.64.0.0/10 VPNs such as Tailscale) and
answers every other address with 403 client_not_on_private_network. Clients
use http://<this machine's LAN address>:8080/v1 with the same relay token.
For access from anywhere, choose any (bearer auth stays required):
airelays init --host 0.0.0.0 --network-scope any # add --force to rewrite an existing config
airelays serve
airelays init prints Who can connect and the matching airelays serve
command. Forward the port on your router and put the relay behind a TLS
reverse proxy or a VPN; Who Can Connect lists
the steps, and Troubleshooting
covers refused connections.
Subscription Status¶
OpenAI subscription usage:
curl http://127.0.0.1:8080/v1/subscription/status \
-H 'authorization: Bearer YOUR_AIRELAYS_TOKEN'
Claude subscription usage (same normalized shape):
curl 'http://127.0.0.1:8080/v1/subscription/status?provider=claude' \
-H 'authorization: Bearer YOUR_AIRELAYS_TOKEN'
See Subscription Status for multi-account parameters and the payload shape.
If a step fails, see Troubleshooting. Next, read API Notes for routes and limits, or Architecture for how requests flow. Back to the README.