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.
  • An optional Claude runtime uses the local claude CLI and its existing subscription auth state.
  • 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.14.1 (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.

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
claude auth login --claudeai
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 claude set-token stores the token in ~/.airelays/claude-token and passes it to the local claude CLI automatically — unlike a shell export, it keeps working under systemd, launchd, and docker. Exporting CLAUDE_CODE_OAUTH_TOKEN still works as a fallback. airelays claude logout signs Claude out completely: it removes the stored token and runs claude auth logout (which signs out every tool using the claude CLI on that machine).

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. Credit details and snapshot times appear under each account's more affordance; 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/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, are rejected loudly.

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 rejected explicitly 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 / json_object map to the CLI's native --json-schema enforcement
  • 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
  • earlier singular AIRelay paths remain compatible for local upgrades

More Docs

Release files for airelays 0.14.1

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.14.1
File Size Uploaded
airelays-0.14.1.tar.gz 6.8 MB Details

Built distribution (wheel)

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

Total release size: 6.9 MB

Release files / airelays-0.14.1.tar.gz

Download URL airelays-0.14.1.tar.gz
Size 6.8 MB
Tags Source
SHA-256 checksum
How to use checksums
36ac95f38953ae643b2b308a34583fb44f8005ac0726ddd0a1026b373c10cc94
BLAKE2b-256 checksum
How to use checksums
67efec7f36bfc13122dc597e89fcdf7afba8f04b833bb3755e97088112c57201
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 Sep 24, 2026.

Transparency log

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

Download URL airelays-0.14.1-py3-none-any.whl
Size 132.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6bde24eff75c9f2a15dd299b9bcf1be88df296a167998083d898738ca32f333c
BLAKE2b-256 checksum
How to use checksums
c2bfe5a5a4d88a85ef19d4af984d2308f10ca3359063514b5f8e199e8e505c46
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 Sep 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.14.1 This release

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