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.
- 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)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 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 โ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
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) โ โ
| 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 |
| 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 |
| 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 |
# 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.yamlreads 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.yamlOr use the higher-level CLI which auto-resolves the canonical path:
aikey proxy start # reads ~/.aikey/config/aikey-proxy.yaml unless --config givenBackground: bugfix 20260521-proxy-config-cwd-first.
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:defaultReplace <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"}]}'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).
AIKEY_PROXY_LOG_LEVEL=debug ./bin/aikey-proxy --config aikey-proxy.yamlThe env var takes precedence over log.level in the system yaml. Useful
for one-off debugging without touching files or restarting the install
flow.
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.
aikey-proxy supports routing outbound AI provider requests through a local proxy.
upstream_proxy:
url: "http://127.0.0.1:7890" # Clash HTTP mode
# url: "socks5://127.0.0.1:7891" # Clash SOCKS5 modeSupported schemes: http, https, socks5.
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.yamlproxychains intercepts at the OS syscall level; no configuration in aikey-proxy is required:
proxychains4 ./bin/aikey-proxy --config aikey-proxy.yamlupstream_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 |
| 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
| 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 |
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)
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)See LICENSE for details.