Skip to main content

AIRelays

AIRelays is a local OpenAI-compatible HTTP server with provider-scoped runtimes.

  • The default runtime uses an AIRelays-owned ChatGPT subscription login.
  • The Claude runtime balances your own subscription accounts through AIRelays-owned local claude CLI profiles; your personal Claude Code sign-in is never used or changed.
  • AIRelays protects the relay with its own bearer token by default.
  • Traffic is logged to JSONL files with automatic rotation and retention (7 days, 1 GiB total by default).

Independence And Intended Use

  • AIRelays is an independent third-party project. It is not affiliated with, endorsed by, or sponsored by any provider.
  • Provider and product names are used only to describe compatibility targets and upstream behavior.
  • AIRelays is designed for a single user running a local relay for personal convenience.
  • AIRelays is not presented as a shared, pooled, multi-user, or resale service.
  • The Claude runtime is local-only and not presented as a sanctioned provider integration path.
  • Personal, local, or noncommercial use does not by itself establish provider permission. You are responsible for checking that your access methods, automation, credential handling, and workloads comply with the applicable terms. AIRelays does not certify compliance; unauthorized use may lead to account suspension or termination, and relay compatibility may stop working without notice.

See DISCLAIMER.md — it links the official Anthropic and OpenAI terms and policy pages to review.

Install

AIRelays ships two ways; both drive the same relay and share the same config (~/.config/airelays) and data (~/.airelays).

Headless relay and CLI (macOS, Linux)

For servers, SSH sessions, Intel Macs, or terminal-first workflows, install the airelays command with one line:

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 without sudo: with uv when available, otherwise into a virtualenv from Python 3.11+ (linked as ~/.local/bin/airelays). On a machine with neither, it installs uv first, which provides Python. Run the same command again to upgrade. Then continue with the Quick Start.

You can also install the package yourself (Python 3.11+, including Windows):

python -m pip install airelays      # or: uv tool install airelays

Or from a source checkout:

python -m pip install .

Desktop app (GUI + system tray)

macOS (Apple Silicon) and Linux (x86_64):

curl -fsSL https://raw.githubusercontent.com/lpalbou/AIRelays/main/scripts/install-desktop.sh | bash

Windows (x64), in PowerShell:

irm https://raw.githubusercontent.com/lpalbou/AIRelays/main/scripts/install-desktop.ps1 | iex

The installers download the newest release's installer from GitHub Releases, verify its SHA-256 digest, install without sudo or admin rights, and start the app:

  • macOS: AIRelays.app in /Applications (~/Applications when /Applications is not writable). A running copy is stopped and replaced.
  • Linux: the AppImage as ~/.local/bin/airelays-desktop, plus an applications-menu entry. Without libfuse2, the launcher uses AppImage's extract-and-run mode.
  • Windows: the NSIS setup, run silently for the current user.

The app is self-contained: it embeds its own Python and relay, so it needs neither Python nor Node. Run the same command again to update. Set AIRELAYS_VERSION=0.16.2 (or $env:AIRELAYS_VERSION on Windows) with any installer to pin a release, and AIRELAYS_NO_LAUNCH=1 to skip starting the app. You can also download the DMG, AppImage, deb, or setup .exe from the Releases page directly; the builds are not notarized or code-signed, see Troubleshooting.

The tray app (desktop/) provides a dashboard with relay start/stop, auth and network modes, OpenAI and Claude sign-in/sign-out, per-account usage bars, a model list with copy-ready ids, live traffic, and diagnostics. The tray icon shows connection state and pulses on request activity; the app can start at login, starts the relay when it opens, and restarts a crashed relay automatically.

In Overview, Connect Your App brings the endpoint, relay key, authentication, and network access controls together. Clicking outside the dashboard hides it without stopping the relay or discarding edits. On macOS and Windows, left-click the tray icon to reopen it; right-click for the menu. Open Dashboard is also available from the tray menu on every platform.

To build the installers from source (Rust and Node required), see desktop/README.md:

cd desktop
./scripts/bundle_runtime.sh
npm install && npm run build

An earlier native macOS status-bar app remains available under macos/AIRelaysMenuBar:

swift build --package-path macos/AIRelaysMenuBar
swift run --package-path macos/AIRelaysMenuBar AIRelaysMenuBar

Quick Start

OpenAI runtime:

airelays init
airelays login
airelays doctor
airelays serve --port 8080

Headless / server install (SSH, no browser):

airelays init
airelays login --device
airelays doctor
airelays serve --port 8080

Device-code login prints a short code you approve from a browser on any other device (laptop, phone). On SSH sessions and displayless Linux, airelays login selects it automatically. Do not paste the browser-flow URL into a browser on another computer: its sign-in redirect only works on the machine running the relay (see docs/troubleshooting.md for the SSH-tunnel alternative).

OpenAI runtime in open local relay mode:

airelays init --no-auth
airelays login
airelays serve --no-auth --port 8080

This disables only the AIRelays client-token gate. It does not bypass the upstream ChatGPT login.

Claude runtime:

airelays init
airelays claude login       # repeat to add another account
airelays serve --port 8080

Claude runtime in headless environments:

# on any machine WITH a browser:
claude setup-token          # prints a long-lived token

# on the server:
airelays init
airelays claude set-token   # paste the token; stored 0600, survives restarts
airelays serve --port 8080

AIRelays uses only Claude accounts it owns. Each airelays claude login creates a separate Claude Code profile under ~/.airelays/claude/accounts/. airelays claude set-token stores an optional setup token 0600 in ~/.airelays/claude-token — unlike a shell export, it keeps working under systemd, launchd, and docker — and runs it as the account default in its own relay-owned Claude Code configuration. Your personal Claude Code sign-in (~/.claude, whatever claude auth login or /login selected), an inherited CLAUDE_CONFIG_DIR, and an exported CLAUDE_CODE_OAUTH_TOKEN are never used, so switching or signing out Claude Code never affects the relay. Until an account is connected, claude:* requests return 503 provider_auth_error and /v1/models lists no Claude models.

airelays claude accounts                     # list account ids and sign-ins
airelays claude login                        # add another subscription
airelays claude login --replace ACCOUNT      # renew one sign-in
airelays claude logout ACCOUNT               # sign out just this account

The desktop Anthropic card offers Sign in / Add account ("In a browser" or "With a token"), separate usage bars, and sign-out on each row. Accounts join and leave routing without a relay restart. The default balanced strategy prefers available execution slots and the lowest reported weekly usage among eligible accounts. Without fresh usage information, accounts take turns. Exhausted short or model-specific windows are skipped; account failures can fail over only before response bytes are sent. Set [providers.claude].balance to round_robin or ordered to change selection.

Usage bars come from Claude Code itself: every five minutes the relay asks each profile's CLI for its usage (get_usage, no prompt or quota), which also keeps idle profiles signed in. This needs a Claude Code version with get_usage (verified with 2.1.292+). The setup-token account is inference-only: Claude reports no usage or email for setup tokens, so it has no bar. See Subscription Status.

Signing out affects only AIRelays: airelays claude logout ACCOUNT signs out that relay-owned profile and stops routing to it, and airelays claude logout default deletes the stored setup token. Your personal Claude Code sign-in is untouched. With multiple accounts, airelays claude logout requires an account or --all.

Upgrading from 0.15.0 or earlier: if Claude only worked through your personal Claude Code sign-in, a custom CLAUDE_CONFIG_DIR, or an exported CLAUDE_CODE_OAUTH_TOKEN, connect it once with airelays claude login (or airelays claude set-token). Profiles already enrolled keep working.

When the Claude runtime is enabled, AIRelays keeps the same auth behavior as the rest of the relay. The default protected mode requires the AIRelays bearer token; --no-auth starts an open local relay. Claude remains restricted to loopback binding.

Basic Verification

Run setup and upstream probes before starting the server:

airelays doctor

List the model ids the running relay accepts (grouped by provider):

airelays models

Use airelays doctor --skip-response to skip the tiny /responses smoke request.

Public health:

curl http://127.0.0.1:8080/healthz

Protected relay status:

curl http://127.0.0.1:8080/v1/relay/status \
  -H 'authorization: Bearer YOUR_AIRELAYS_TOKEN'

OpenAI model listing:

curl http://127.0.0.1:8080/v1/models \
  -H 'authorization: Bearer YOUR_AIRELAYS_TOKEN'

OpenAI text request:

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"}]
  }'

Claude text request:

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"}]
  }'

Multiple OpenAI Accounts

One person can enroll several of their own OpenAI subscriptions and let the relay balance across them. Signing in again with a different account adds it (the previous sign-in is kept, never overwritten):

airelays login            # first account
airelays login            # second account — added alongside the first
airelays accounts         # list accounts and the commands to manage them
airelays logout perso@gmail.com          # sign one account out
airelays accounts order work@company.com perso@gmail.com   # change priority

airelays accounts is the hub: it lists your accounts in balancing order and prints the exact commands to add, sign out, or reorder them. In the desktop app, each account row has a sign-out button and the "Add account" button offers both browser and code (headless) sign-in.

By default AIRelays balances requests by remaining capacity (balance = "balanced"): the account with the most unused weekly quota serves next, so consumption equalizes as a percentage of each plan's own capacity — a small Plus plan and a large Enterprise plan deplete proportionally instead of the small plan draining many times faster. Which usage windows a plan reports is upstream policy (some plans report only a weekly window), so the relay identifies windows by duration and balances on each account's longest one. The relay probes each account's usage at launch and refreshes it in the background; an account at a usage limit is benched until that window resets and rejoins rotation automatically. Alternatives: balance = "round_robin" sends strictly equal request counts, and balance = "ordered" drains the first account before touching the next. Failed-over requests are logged with the serving account, and /v1/subscription/status?all_accounts=true reports usage per account.

Multiple accounts exist so one user can use their own subscriptions from one relay; it is not a mechanism for sharing or pooling access between people (see DISCLAIMER.md).

Relay Token

Show the current token:

airelays token show

Rotate the current token:

airelays token rotate

Use the relay token as the client credential when you point an OpenAI-compatible SDK at AIRelays.

Provider Routing

  • models starting with claude: or claude- use the Claude runtime when it is enabled
  • other model ids use the OpenAI runtime when it is enabled
  • OpenAI model discovery queries the upstream catalog using the installed Codex client version, with a bundled version floor for standalone installations. Optional [providers.openai] extra_models entries extend the catalog; other unlisted ids are rejected locally when the catalog is available.
  • Claude model discovery queries the installed CLI and exposes both aliases and concrete model ids. The Models tab and airelays models show each reported alias resolution, such as claude:fable resolving to claude-fable-5-1.
  • The Models tab refreshes automatically every five minutes while reachable. Its Refresh button, or GET /v1/models?refresh=true, requests fresh provider catalogs. See model discovery for cache and availability limits.
  • With multiple OpenAI accounts, /v1/models is the union of their catalogs. Balancing, conversation affinity, and failover stay within each model's supporting account subset. The Models tab shows account coverage and labels entries the upstream hides from its own picker.
  • Subscription bars report upstream allowances, including Claude's separately scoped Fable weekly cap when present. Hover over or activate the ? beside an account name for credit details and snapshot times; percentages are not token counts. See Subscription Status.
  • AIRelays rejects requests when the selected runtime is disabled or the route is outside that runtime's published subset

What AIRelays Exposes

  • GET /v1/models
  • GET /v1/models/{model}
  • GET /v1/subscription/status (OpenAI and ?provider=claude)
  • GET /v1/account/rate_limits
  • GET /v1/relay/status
  • POST /v1/relay/accounts/refresh
  • POST /v1/responses
  • POST /v1/chat/completions
  • POST /v1/completions
  • POST /v1/files
  • GET /v1/files
  • GET /v1/files/{file_id}
  • GET /v1/files/{file_id}/content
  • DELETE /v1/files/{file_id}
  • POST /v1/conversations
  • GET /v1/conversations/{conversation_id}
  • POST /v1/conversations/{conversation_id}
  • DELETE /v1/conversations/{conversation_id}
  • /no-tools/v1/models
  • /no-tools/v1/responses
  • /no-tools/v1/chat/completions
  • /no-tools/v1/completions

What The Relay Changes (Compatibility Layer)

The ChatGPT subscription backend is not the public OpenAI platform API, so AIRelays adapts some requests instead of letting them fail. Parameter stripping is always visible: removed parameters are logged as a compatibility_adaptation record in the traffic logs and reported in the x-airelays-ignored-parameters response header. Other compatibility normalizations are documented below and may log dedicated adaptation records when the request shape itself is repaired.

Sampling parameters are removed. The upstream rejects temperature, top_p, presence_penalty, and frequency_penalty outright ("Unsupported parameter: temperature"). AIRelays strips them so standard SDK calls keep working; generation then runs with the upstream's own sampling defaults, which cannot be overridden. The Claude routes apply the same adaptation — the local claude CLI has no sampling controls — so the same SDK calls work against claude:* models too.

Output-token limits are removed. The subscription upstreams do not honor client-set output caps (max_tokens, max_completion_tokens, max_output_tokens), so AIRelays strips them instead of failing the request; responses run to the model's natural stop.

Cursor BYOK chat-route compatibility is normalized locally. Some current Cursor builds send malformed OpenAI-compatible requests to /v1/chat/completions: either full Responses-style bodies (input, instructions, flat tools, etc.) or flat Responses-style custom tools/tool choices/tool calls such as ApplyPatch. AIRelays accepts those shapes on the chat route, normalizes them to the Responses upstream, and translates upstream custom_tool_call items back to chat-completions tool_calls on both streaming and non-streaming responses. Requests that mix messages and input, or tool outputs that do not reference a preceding assistant tool call in the same request (or an earlier turn of its conversation), are rejected loudly.

Unrecognized parameters are disclosed, not silently dropped. On chat and completions, a parameter AIRelays does not recognize is removed and listed in x-airelays-ignored-parameters with the stripped ones. Parameters that would change the output and cannot be honored (stop, logprobs, logit_bias, web_search_options, moderation, and others listed in docs/api.md) are rejected with a 422 instead.

Reasoning effort is forwarded, not invented. reasoning_effort (chat completions) and reasoning: {"effort": ...} (responses) pass through to the upstream unchanged. Every model's supported modes are published in /v1/models under airelays.reasoning, using provider catalog metadata when available. Modes vary by model and may include max or ultra. Claude modes map to the local CLI's --effort flag; unsupported values are rejected with the model's supported list. When omitted, the provider chooses its default; Claude can use an adaptive default. To choose reasoning depth explicitly:

curl http://127.0.0.1:8317/v1/chat/completions \
  -H 'authorization: Bearer YOUR_AIRELAYS_TOKEN' \
  -H 'content-type: application/json' \
  -d '{
    "model": "gpt-5.5",
    "reasoning_effort": "medium",
    "messages": [{"role": "user", "content": "..."}]
  }'

Conversations stick to one account. With multiple OpenAI accounts, a conversation keeps using the account that served its first turn (preserving upstream prompt caching); it only fails over to another account at a turn boundary when the pinned account is at its limit.

Failed calls are retried automatically. Transient upstream failures (e.g. server_is_overloaded) are retried with exponential backoff — by default 3 retries waiting 5s/20s/60s, each re-running account failover — as long as no response byte has reached the client. A retry that succeeds returns the normal response; a request that keeps failing returns OpenAI-shaped error JSON with the real HTTP status and the upstream's own reason. Tune with retry_attempts / retry_backoff_seconds ([providers.openai], desktop Settings → Providers; 0 disables). Retries appear in the traffic log as retry_backoff records.

Compatibility Boundary

OpenAI runtime:

  • first-class routes: /v1/responses, /v1/chat/completions, /v1/completions
  • local files and local conversations are supported
  • non-stream responses are reconstructed from streamed upstream events
  • store=true is rejected
  • output-token limit fields are stripped and disclosed on the OpenAI-shaped text-generation routes

Claude runtime:

  • discovered Claude aliases and concrete model ids, plus configured overrides
  • supported routes: text /v1/chat/completions and text /v1/completions
  • stateless only
  • no /v1/responses
  • no files, images, audio, or tools
  • structured outputs on chat completions: response_format json_schema maps to the CLI's native --json-schema enforcement; json_object answers are checked to be one JSON object
  • reasoning_effort maps to the CLI's --effort (low, medium, high, xhigh, max)
  • no AIRelays local conversation reuse
  • sampling parameters are stripped and disclosed, like on the OpenAI runtime

Security Defaults

  • default listener: 127.0.0.1:8080
  • protected routes: /v1/* and /no-tools/v1/*
  • public routes: / and GET /healthz
  • protected diagnostics: GET /v1/relay/status
  • default rate limit: 120 requests/minute with burst 40
  • default concurrent request cap: 8 per IP
  • repeated bad tokens trigger a temporary IP block
  • the Claude runtime is loopback-only and follows the relay's protected or open local auth mode

Configuration

Traffic logs are bounded by default: up to 7 days, 1 GiB total, and 50 MiB per file, with hourly rotation and oldest-first cleanup. A busy relay may keep less history because the disk limit takes precedence. Use airelays logs --retention-days 30 for a month, or the tray app's Settings → Traffic log retention controls. Changes persist without a restart; GET/PUT /v1/relay/logging expose the same policy and current usage. Starting the upgraded relay also applies the limits to existing traffic logs. See retention configuration.

AIRelays reads configuration in this order:

  1. CLI flags
  2. AIRELAYS_* environment variables
  3. legacy OPENAI_ENDPOINT_* migration variables where supported
  4. ~/.config/airelays/config.toml
  5. built-in defaults

Important toggles:

  • AIRELAYS_REQUIRE_BEARER_AUTH
  • AIRELAYS_BEARER_TOKEN
  • AIRELAYS_BEARER_TOKEN_FILE
  • AIRELAYS_ENABLE_OPENAI
  • AIRELAYS_OPENAI_MODELS_CACHE_TTL_SECONDS
  • AIRELAYS_ENABLE_CLAUDE
  • AIRELAYS_CLAUDE_BIN
  • AIRELAYS_CLAUDE_MODELS

Paths

  • config: ~/.config/airelays/config.toml
  • data dir: ~/.airelays
  • logs: ~/.airelays/logs
  • relay token: ~/.airelays/relay-token
  • Claude accounts: ~/.airelays/claude/accounts/<id>/; setup token: ~/.airelays/claude-token
  • earlier singular AIRelay paths remain compatible for local upgrades

More Docs

Metadata

Release files for airelays 0.16.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for airelays 0.16.2
File Size Uploaded
airelays-0.16.2.tar.gz 6.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for airelays 0.16.2
File Interpreter ABI Platform
airelays-0.16.2-py3-none-any.whl Python 3 none any Details

Total release size: 7.0 MB

Release files / airelays-0.16.2.tar.gz

Download URL airelays-0.16.2.tar.gz
Size 6.9 MB
Tags Source
SHA-256 checksum
How to use checksums
f1fac5a3a0a48ee076aff237409f4596644b9e3f9fe7558f8559682c7585dc46
BLAKE2b-256 checksum
How to use checksums
56989b779f191d9535b036bbad430c03e4d13ae6104514c047377c2389494b28
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / airelays-0.16.2-py3-none-any.whl

Download URL airelays-0.16.2-py3-none-any.whl
Size 165.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f1156a0a0e0ca7defb503493a7f36eafe14b9578cfbd0c8da1dc2445f95e3c34
BLAKE2b-256 checksum
How to use checksums
1655bc2f5c18d5d169f101a8311a6b309f0ac2d1efc5d74a1b3dca3843b8df80
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

0.17.1

2 release files

0.17.0

2 release files

This release

0.16.2 This release

2 release files

0.16.1

2 release files

0.16.0

2 release files

0.15.0

2 release files

0.14.1

2 release files

0.12.5

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page