Skip to content

Latest commit

ย 

History

320 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

aikey-proxy

AiKey local proxy โ€” the core execution point for Stage 2 MVP.

Runs on the developer's local machine, receives requests with virtual keys, replaces them with real provider keys, and forwards to AI providers.

Responsibilities

  • Virtual key (aikey_vk_*) โ†’ real key substitution
  • OpenAI / Anthropic dual-protocol compatible proxy
  • SSE streaming response passthrough
  • Reads existing Rust vault (Argon2id + AES-256-GCM)
  • Asynchronous usage event recording (SQLite WAL)
  • Model allowlist policy enforcement
  • Local admin API (health / status / metrics)

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Developer CLI / IDE / SDK   โ”‚
โ”‚  (Cursor, Claude, Pythonโ€ฆ)   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
           โ”‚  Authorization: Bearer aikey_vk_xxx
           โ”‚  or x-api-key: aikey_vk_xxx
           โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           aikey-proxy  (127.0.0.1:27200)     โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ vkeys   โ”‚โ†’ โ”‚ provider โ”‚โ†’ โ”‚ httputil.  โ”‚  โ”‚
โ”‚  โ”‚ registryโ”‚  โ”‚ adapter  โ”‚  โ”‚ Reverse    โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚ Proxy      โ”‚  โ”‚
โ”‚       โ”‚                     โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”                      โ”‚         โ”‚
โ”‚  โ”‚  vault  โ”‚  real key            โ”‚         โ”‚
โ”‚  โ”‚ reader  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                โ”‚
โ”‚       โ”‚           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚
โ”‚       โ”‚           โ”‚ events       โ”‚          โ”‚
โ”‚       โ”‚           โ”‚ collector    โ”‚โ”€โ”€โ†’ SQLite โ”‚
โ”‚       โ”‚           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   WAL    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
        โ”‚  Reads ~/.aikey/data/vault.db (read-only)
        โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  AiKey Vault     โ”‚        โ”‚  AI Provider     โ”‚
โ”‚  (Rust CLI)      โ”‚        โ”‚  OpenAI / Claude โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Call Sequence

Client                    aikey-proxy                Vault          Provider
  โ”‚                           โ”‚                        โ”‚               โ”‚
  โ”‚  POST /v1/chat/completionsโ”‚                        โ”‚               โ”‚
  โ”‚  Bearer aikey_vk_xxx      โ”‚                        โ”‚               โ”‚
  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚                        โ”‚               โ”‚
  โ”‚                           โ”‚ 1. extractVirtualKey   โ”‚               โ”‚
  โ”‚                           โ”‚ 2. registry.Resolve    โ”‚               โ”‚
  โ”‚                           โ”‚ 3. checkModelAllowlist โ”‚               โ”‚
  โ”‚                           โ”‚โ”€โ”€โ”€GetSecret(alias)โ”€โ”€โ”€โ”€โ–ถโ”‚               โ”‚
  โ”‚                           โ”‚โ—€โ”€โ”€real API keyโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚               โ”‚
  โ”‚                           โ”‚ 4. provider.Rewrite    โ”‚               โ”‚
  โ”‚                           โ”‚    (swap key + host)   โ”‚               โ”‚
  โ”‚                           โ”‚โ”€โ”€โ”€โ”€real key requestโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚
  โ”‚                           โ”‚โ—€โ”€โ”€โ”€response (or SSE stream)โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
  โ”‚โ—€โ”€โ”€responseโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚                        โ”‚               โ”‚
  โ”‚                           โ”‚ 5. async: record event โ”‚               โ”‚
  โ”‚                           โ”‚    โ†’ events.db (WAL)   โ”‚               โ”‚

Data Flow

Phase Direction Data
Inbound Client โ†’ Proxy Virtual key + request body
Resolution Proxy internal token โ†’ registry โ†’ route (provider / base_url / key_alias)
Secret Proxy โ†’ Vault alias โ†’ decrypted real key (in-memory cache)
Outbound Proxy โ†’ Provider Real key + original request body
Response Provider โ†’ Proxy โ†’ Client Passthrough (SSE streaming: FlushInterval=-1)
Audit Proxy โ†’ events.db Async batch write to SQLite WAL

Tech Stack

Component Choice Rationale
Language Go 1.26 Cross-platform, single binary
Proxy core net/http + httputil.ReverseProxy Lightweight and controllable, no heavy framework
SQLite modernc.org/sqlite Pure Go, no CGO, easy cross-compilation
KDF golang.org/x/crypto/argon2 Compatible with Rust vault
AEAD crypto/aes + GCM Compatible with Rust vault
Config YAML (gopkg.in/yaml.v3) Good readability

Runtime Environment

Item Requirement
Go >= 1.26.1 (build only)
OS macOS (arm64), Linux (amd64), Windows (amd64)
Disk ~50 MB (binary + vault + events DB)
Memory ~20 MB RSS (idle), scales with concurrent requests
Network Localhost only (127.0.0.1:27200 by default)
Dependencies None at runtime (single static binary)
Prerequisite AiKey vault (~/.aikey/data/vault.db) created by aikey-cli

Quick Start

# Build
make build

# Prepare config (see aikey-proxy.yaml.example)
cp aikey-proxy.yaml.example aikey-proxy.yaml
# Adjust listen / vault / events sections as needed; virtual keys come
# from vault (see "Get a virtual-key bearer token" below).

# Start (requires master password)
export AIKEY_MASTER_PASSWORD="your-password"
./bin/aikey-proxy --config aikey-proxy.yaml

# Or enter password interactively
./bin/aikey-proxy --config aikey-proxy.yaml

# Verify
curl http://127.0.0.1:27200/health

โš ๏ธ Dev-loop note (2026-05-21): invoking the binary directly with a relative --config aikey-proxy.yaml reads this repo's dev fixture, which is a schema sample, NOT the runtime config that installs use. For day-to-day dev iteration prefer:

# System layer is rendered by aikey-config-tool to ~/.aikey/config/
aikey-config-tool render --profile personal
./bin/aikey-proxy --config ~/.aikey/config/aikey-proxy.yaml

Or use the higher-level CLI which auto-resolves the canonical path:

aikey proxy start   # reads ~/.aikey/config/aikey-proxy.yaml unless --config given

Background: bugfix 20260521-proxy-config-cwd-first.

Get a virtual-key bearer token

Virtual keys are issued by aikey-cli and stored in the vault. The proxy loads them at startup (managed-keys cache + personal route tokens).

# Add a personal API key (alias is positional, provider is the flag)
aikey add openai:default --provider openai

# List all keys; the route_token column is the bearer to use in requests
aikey list

# Print proxy-friendly client config (URL + bearer)
aikey route openai:default

Usage Examples

Replace <route_token> with the value from aikey list / aikey route.

# OpenAI compatible
curl -X POST http://127.0.0.1:27200/v1/chat/completions \
  -H "Authorization: Bearer <route_token>" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}'

# Anthropic compatible
curl -X POST http://127.0.0.1:27200/v1/messages \
  -H "x-api-key: <route_token>" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{"model":"claude-sonnet-4-5-20250929","max_tokens":1024,"messages":[{"role":"user","content":"Hello"}]}'

Configuration files

aikey-proxy reads aikey-proxy.yaml (system) plus optionally an aikey-user.yaml (user-owned) from the same directory:

OS Default config dir
Linux / macOS ~/.aikey/config/
Windows %LOCALAPPDATA%\Aikey\config\

aikey-user.yaml is created on first trial install or when running local-install.sh --with-console. Personal-only installs (CLI + proxy without console) don't write a user file โ€” proxy section currently has no user-owned fields. Service loads run a system + user merge in memory (user values win on field collision).

Adjusting log level without editing yaml

AIKEY_PROXY_LOG_LEVEL=debug ./bin/aikey-proxy --config aikey-proxy.yaml

The env var takes precedence over log.level in the system yaml. Useful for one-off debugging without touching files or restarting the install flow.

Logging conventions

This service follows the project-wide logging spec โ€” every silent-fail path (parser fallthrough, missing field, shape mismatch) must emit a WARN, callers add a second-layer "2xx + non-empty body + zero result" defense, and event.name / error.code come from a central enum (internal/observability/handler.go). New extractors must ship fixture-based tests that assert WARN emission on every failure path.

See logging-conventions.md for the full spec and the 2026-05-07 incident that motivated it (codex/Responses-API silent-zero token loss).

Full design (system / user split, migrate-config-split upgrade flow, removed-registry, deprecation rules): roadmap20260320/ๆŠ€ๆœฏๅฎž็Žฐ/ๅผ€ๆบ็‰ˆๆœฌๆ–นๆกˆ/config-split-system-user.md.

Outbound Proxy (VPN / Clash / proxychains)

aikey-proxy supports routing outbound AI provider requests through a local proxy.

Option 1 โ€” Config file (recommended)

upstream_proxy:
  url: "http://127.0.0.1:7890"    # Clash HTTP mode
  # url: "socks5://127.0.0.1:7891"  # Clash SOCKS5 mode

Supported schemes: http, https, socks5.

Option 2 โ€” Environment variables

Go's standard library reads these automatically; no config change needed:

export HTTPS_PROXY=http://127.0.0.1:7890   # Clash HTTP
export HTTPS_PROXY=socks5://127.0.0.1:7891 # Clash SOCKS5
export NO_PROXY=127.0.0.1,localhost         # don't proxy local admin API
./bin/aikey-proxy --config aikey-proxy.yaml

Option 3 โ€” proxychains (Linux)

proxychains intercepts at the OS syscall level; no configuration in aikey-proxy is required:

proxychains4 ./bin/aikey-proxy --config aikey-proxy.yaml

Priority

upstream_proxy.url (config) > HTTPS_PROXY env var > direct connection.

Scenario Recommended method
Clash for Windows (HTTP) upstream_proxy.url: http://127.0.0.1:7890
Clash SOCKS5 upstream_proxy.url: socks5://127.0.0.1:7891
System VPN (all traffic tunneled) No config needed โ€” works transparently
proxychains on Linux Run with proxychains4, no config needed

Admin API

Endpoint Description
GET /health Health check
GET /status Uptime, virtual key count, vault status
GET /metrics Per virtual-key / provider request statistics

OAuth API (via aikey-auth-broker)

Provider OAuth account management โ€” login, token lifecycle, credential resolution.

Endpoint Method Description
/oauth/login POST Start login (returns auth_url) or submit code (returns account)
/oauth/status GET Poll login session status
/oauth/poll POST Poll Device Code completion (Kimi)
/oauth/logout POST Remove account and tokens
/oauth/accounts GET List all OAuth accounts
/oauth/accounts/{id}/health GET Token health (valid/expiring/expired)
/oauth/accounts/{id}/display-identity POST Set display name (Kimi: no email)

OAuth credentials inject provider-specific persona headers during proxy forwarding:

  • Claude: anthropic-beta + X-Stainless-* + X-Claude-Code-Session-Id + metadata.user_id
  • Codex: originator: opencode + ChatGPT-Account-Id
  • Kimi: X-Msh-Platform: kimi_cli + User-Agent: KimiCLI/1.24.0

Error Codes

Code HTTP Description
TOKEN_MISSING 401 Missing aikey_vk_* token in request
TOKEN_INVALID 401 Token not found in registry
POLICY_MODEL_FORBIDDEN 403 Model not in allowlist
VAULT_ERROR 502 Cannot find matching real key in vault
UPSTREAM_ERROR 502 Cannot connect to upstream provider
OAUTH_NOT_AVAILABLE 503 OAuth broker not initialized
OAUTH_TOKEN_EXPIRED 401 OAuth token expired, re-login required
OAUTH_RESOLVE_FAILED 503 Cannot resolve OAuth credential

Project Structure

cmd/aikey-proxy/main.go      Entry point, component wiring, graceful shutdown
internal/
  config/                    YAML config parsing and validation
  vault/                     Rust vault compatible reader + OAuth token/account stores
  vkeys/                     Virtual key registry (RWMutex)
  provider/                  OpenAI / Anthropic / Generic adapters
  proxy/                     Core reverse proxy
  events/                    Async event collection + SQLite WAL
  admin/                     Admin API handlers
  server/                    HTTP server lifecycle
scripts/
  dev-setup.sh               Local dev environment setup (macOS / Windows WSL)
  deploy-integration.sh      Integration environment deployment (systemd)
  deploy-production.sh       Production โ€” Ubuntu / CentOS / macOS (auto-detects remote OS)
  deploy-production.ps1      Production โ€” Windows (PowerShell / WinRM)

Deployment

Three environment deployment scripts are provided in the scripts/ directory:

Script Environment Target Platform Description
dev-setup.sh Local dev macOS / Linux / Windows WSL Go check, build, config init, dev tools install
deploy-integration.sh Integration / Staging Ubuntu / CentOS (systemd) Cross-compile + systemd service, local or remote SSH
deploy-production.sh Production (Shell) Ubuntu / CentOS / macOS Auto-detects remote OS, systemd / launchd, backup + health check
deploy-production.ps1 Production (PowerShell) Windows WinRM local/remote, NSSM service, backup + health check
# Local development
./scripts/dev-setup.sh

# Integration (remote Linux)
./scripts/deploy-integration.sh --host user@staging-host --config staging.yaml

# Production โ€” Ubuntu / CentOS (remote OS auto-detected)
./scripts/deploy-production.sh --host user@prod-host --config prod.yaml --vault /path/to/vault.db

# Production โ€” macOS
./scripts/deploy-production.sh --host user@mac-host --config prod.yaml --vault /path/to/vault.db
# Production โ€” Windows local
.\scripts\deploy-production.ps1 -Config C:\prod.yaml -Vault C:\vault.db

# Production โ€” Windows remote (requires WinRM)
.\scripts\deploy-production.ps1 -ComputerName server01 -Config C:\prod.yaml -Credential (Get-Credential)

License

See LICENSE for details.

About

A local AI API proxy that routes requests with virtual keys, enforces team rules, tracks usage, and supports offline fallback.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages