Skip to main content

AIRelays: an independent OpenAI-compatible local relay for single-user subscription-backed access.

Project description

AIRelays

AIRelays is an independent local OpenAI-compatible HTTP server backed by a ChatGPT subscription login that AIRelays stores independently. It exposes the verified OpenAI-shaped routes this upstream can support, protects the local relay with its own bearer token, and logs every transit to hourly JSONL files.

POST /v1/responses keeps the general OpenAI Responses envelope, but parameter parity is not complete. Some fields pass through unchanged, some are adapted for the subscription backend, and unsupported fields are rejected or omitted explicitly.

AIRelays does not require a user-supplied OpenAI platform API key for upstream inference. Instead, it uses the same upstream ChatGPT login protocol that Codex uses while keeping AIRelays auth storage separate from Codex storage. Clients that call AIRelays should use the relay bearer token as the local client credential they present to AIRelays.

Independence And Intended Use

  • AIRelays is an independent third-party project. It is not affiliated with, endorsed by, or sponsored by OpenAI.
  • 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.
  • You are responsible for complying with the terms and usage policies that apply to any upstream account or subscription you use with AIRelays.

See DISCLAIMER.md for the short project notice.

Quick Start

python -m pip install .
airelays init
airelays login
airelays doctor
airelays serve --port 8080

If you are installing from a published package instead of a source checkout, use python -m pip install airelays.

If you want a local relay with no client-side bearer auth, use:

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

This disables only the AIRelays client token gate. Model routes still require a valid upstream ChatGPT login from airelays login.

Existing local AIRelay state is recognized for compatibility. If you already have singular-path state such as ~/.config/airelay, ~/.airelay, or an older AIRelay Auth keychain entry, AIRelays can continue using it without sharing runtime state with Codex.

Smoke test the public and protected surfaces:

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

In open local relay mode, the same GET /v1/relay/status request works without the Authorization header.

Verify protected model access and a simple query:

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

Verify the same calls in open local relay mode:

curl http://127.0.0.1:8080/v1/models

curl http://127.0.0.1:8080/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{
    "model": "gpt-5.5",
    "messages": [{"role": "user", "content": "Reply with exactly: AIRelays OK"}]
  }'

Inspect the resolved relay and upstream-auth state at any point:

airelays status
airelays doctor

CLI status and setup commands default to readable terminal output. Use --json on airelays init, airelays status, airelays doctor, airelays logout, airelays token show, or airelays token rotate when you need machine-readable output for automation. Use airelays doctor --skip-response when you want setup and model checks without sending the tiny /responses smoke request.

Point your client at:

http://127.0.0.1:8080/v1

Use the token generated by airelays init as the client credential when you point an OpenAI-compatible SDK at AIRelays. Standard OpenAI SDKs will then send Authorization: Bearer <relay-token> automatically.

If you launch with --no-auth or AIRELAYS_REQUIRE_BEARER_AUTH=false, clients can call the relay without an Authorization header. If an SDK still requires an api_key field, any non-empty placeholder string works in that mode.

If you want to provide the relay token yourself instead of using the default token file, launch the server with:

AIRELAYS_BEARER_TOKEN='YOUR_AIRELAYS_TOKEN' airelays serve --port 8080

or point AIRelays at a specific token file:

airelays serve --bearer-token-file /path/to/relay-token --port 8080

What AIRelays Does

  • Uses the same upstream login protocol as Codex browser login and device-code login.
  • Stores upstream auth under AIRelays-owned state instead of reusing ~/.codex.
  • Generates and persists a separate relay bearer token for client-to-relay access.
  • Can run in open local relay mode with bearer auth disabled.
  • Protects /v1/* and /no-tools/v1/* with bearer auth, per-IP rate limits, concurrent-request caps, and temporary blocks after repeated bad tokens.
  • Exposes OpenAI-compatible routes for:
    • GET /v1/models
    • GET /v1/subscription/status
    • GET /v1/account/rate_limits
    • POST /v1/completions
    • POST /v1/responses
    • POST /v1/chat/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/completions
    • /no-tools/v1/responses
    • /no-tools/v1/chat/completions
  • Logs inbound requests, endpoint rejects, outbound responses, upstream requests, upstream responses, stream lines, and usage summaries to logs/YYYY/MM/DD-HH.log.

First-Run Flow

  1. airelays init
    • writes ~/.config/airelays/config.toml if it does not already exist
    • creates ~/.airelays/relay-token with 0600 permissions if a relay token is missing
    • prints a formatted setup summary and reveals the token only when it was newly created
  2. airelays init --no-auth
    • writes ~/.config/airelays/config.toml with bearer auth disabled
    • does not create or require a relay token
  3. airelays login
    • creates an AIRelays-owned ChatGPT subscription session
  4. airelays doctor
    • checks local config, relay-token setup, upstream OpenAI subscription auth, live /models, and a tiny /responses request
    • supports --json for automation and --skip-response to avoid the live response smoke request
  5. airelays serve --port 8080
    • starts the protected local endpoint
    • fails fast if bearer auth is enabled but no relay token is configured
    • prints the client base URL, token file path, and the required Authorization header shape
  6. airelays serve --no-auth --port 8080
    • starts an open local endpoint with no relay-token check
    • keeps the normal per-IP rate limits and concurrency limits

You can show the current relay token at any time:

airelays token show

You can also rotate the relay token later:

airelays token rotate

Example Client Usage

Python with the OpenAI SDK:

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8080/v1",
    api_key="YOUR_AIRELAYS_TOKEN",
)

response = client.responses.create(
    model="gpt-5.4-mini",
    input="Summarize the purpose of AIRelays.",
)
print(response.output_text)

Raw curl:

curl http://127.0.0.1:8080/v1/responses \
  -H 'authorization: Bearer YOUR_AIRELAYS_TOKEN' \
  -H 'content-type: application/json' \
  -d '{
    "model": "gpt-5.4-mini",
    "input": "Summarize the purpose of AIRelays.",
    "stream": false
  }'

Shell example with a relay-token environment variable:

export OPENAI_BASE_URL='http://127.0.0.1:8080/v1'
export AIRELAYS_TOKEN="$(tr -d '\n' < ~/.airelays/relay-token)"

If your SDK insists on an api_key argument, pass the relay token from AIRELAYS_TOKEN.

Open local relay mode with a placeholder value for SDKs that insist on one:

export OPENAI_BASE_URL='http://127.0.0.1:8080/v1'
export AIRELAYS_CLIENT_PLACEHOLDER='local-open-relay'

Verified Compatibility Boundary

This server is intentionally explicit about what is and is not verified.

  • Inference uses https://chatgpt.com/backend-api/codex.
  • Subscription status uses https://chatgpt.com/backend-api/wham/usage.
  • The upstream requires stream=true, so non-stream OpenAI responses are reconstructed locally from streamed event sequences.
  • The upstream requires store=false, so requests that try to enable upstream storage are rejected with 422.
  • The verified subscription backend does not currently accept output-token limit parameters on the OpenAI-shaped text-generation routes, so AIRelays rejects max_output_tokens on /v1/responses, max_completion_tokens on /v1/chat/completions, and max_tokens on /v1/completions explicitly with 422.
  • The upstream requires non-empty instructions, so the compatibility layer injects the minimal verified placeholder "." only when the caller omitted instructions entirely.
  • Image input is supported.
  • input_file supports external file_url, inline data URLs, raw Base64 plus filename, and AIRelays local file_id values from POST /v1/files.
  • Text and JSON-like document input is also supported by local inlining up to 1 MB when callers use local text-file references on chat-style routes.
  • Local file uploads are capped at 32 MiB each and 256 MiB total by default.
  • Audio input, embeddings, image generation, realtime sessions, and other unverified routes return explicit 501 unsupported_error.

Security Defaults

  • Listener default: 127.0.0.1:8080
  • Protected routes: /v1/* and /no-tools/v1/*
  • Public routes: / and a minimal GET /healthz
  • Protected diagnostics: GET /v1/relay/status
  • Relay auth: bearer token required by default
  • Token storage: ~/.airelays/relay-token
  • Default rate limit: 120 requests/minute with burst 40
  • Default concurrent request cap: 8 per IP
  • Default repeated-auth-failure block: 8 bad attempts in 300 seconds -> 900 second block

See Security for the full behavior.

Configuration

AIRelays reads configuration in this order:

  1. explicit CLI flags such as --config, --port, or --auth-storage
  2. AIRELAYS_* environment variables
  3. legacy OPENAI_ENDPOINT_* environment variables where supported as a migration fallback
  4. ~/.config/airelays/config.toml
  5. built-in defaults

auth.storage = "auto" prefers the AIRelays keyring namespace and falls back to ~/.airelays/auth.json when keyring access is unavailable. If earlier AIRelay config or data directories already exist, AIRelays keeps using them for compatibility. In keyring-backed setups, AIRelays also recognizes earlier AIRelay Auth entries and migrates them into the AIRelays-owned namespace when they are encountered.

Important paths:

  • config: ~/.config/airelays/config.toml
  • data dir: ~/.airelays
  • upstream auth fallback file: ~/.airelays/auth.json
  • logs: ~/.airelays/logs
  • relay token: ~/.airelays/relay-token

To override the default token source at launch time:

  • AIRELAYS_BEARER_TOKEN
  • airelays serve --bearer-token-file /path/to/relay-token

To launch without relay auth:

  • airelays init --no-auth
  • airelays serve --no-auth
  • AIRELAYS_REQUIRE_BEARER_AUTH=false

See Configuration for field details and a sample config.

Publication Surface

  • package name: airelays
  • CLI command: airelays
  • Python package: airelays

Documentation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

airelays-0.2.5.tar.gz (78.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

airelays-0.2.5-py3-none-any.whl (53.2 kB view details)

Uploaded Python 3

File details

Details for the file airelays-0.2.5.tar.gz.

File metadata

  • Download URL: airelays-0.2.5.tar.gz
  • Upload date:
  • Size: 78.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for airelays-0.2.5.tar.gz
Algorithm Hash digest
SHA256 0d6d44b46089d0852c384bdc0accedf180c7d8bb6b6215b4386749bc5250d5bc
MD5 9860768d5983756e85f9e7f4e7ad6aff
BLAKE2b-256 4e742f56632b46574c7cf3d1818e8d5f0621ad6646a0c04e80dc56be633c9d69

See more details on using hashes here.

Provenance

The following attestation bundles were made for airelays-0.2.5.tar.gz:

Publisher: release.yml on lpalbou/AIRelays

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file airelays-0.2.5-py3-none-any.whl.

File metadata

  • Download URL: airelays-0.2.5-py3-none-any.whl
  • Upload date:
  • Size: 53.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for airelays-0.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 6ade97b488f450388bf2309f63c288c290329a52dca89832c55385f6a4dce5c5
MD5 df1157f3243d9f924f0a0fe8a188472a
BLAKE2b-256 e652b04dd47683386655112f5e74118d681501dd4a32b2be3f55f65ad8f54d54

See more details on using hashes here.

Provenance

The following attestation bundles were made for airelays-0.2.5-py3-none-any.whl:

Publisher: release.yml on lpalbou/AIRelays

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page