Skip to main content

Run any agent (Claude, Codex, custom) on any machine — with no API key on the machine. A secure, self-hosted proxy for models and tools.

Project description

proxyagent

Run any agent — Claude, Codex, custom — on any machine, with no API key on the machine.

A secure, self-hosted proxy for models and tools. Your keys live in one hardened place; every machine holds only a scoped, revocable token.


Agents need model access (and tool access) to do anything. Today that means scattering real API keys across every machine an agent runs on — a security nightmare. proxyagent fixes it: stand up one proxy that holds the real credentials, and point every agent at it. The machine gets a throwaway token; the real key never leaves the proxy.

   remote machine                     proxy (you host)            upstream
 ┌────────────────┐  token only   ┌──────────────────┐  real key  ┌───────────┐
 │ claude / codex │ ───────────►  │  proxyagent serve │ ─────────► │ Anthropic │
 │  (no real key) │ ◄───────────  │  scope·log·tools  │ ◄───────── │  OpenAI   │
 └────────────────┘   stream      └──────────────────┘            └───────────┘

How it works

Every harness honours *_BASE_URL, so the shim is trivial: point the base URL at the proxy and use the machine token as the "api key." The proxy authenticates the token, checks its scope, swaps in the real key, forwards upstream, and logs the call. The machine never sees a real credential.

Try it with zero keys (local)

pip install proxyagent && proxyagent serve        # prints an admin token
proxyagent token new local        # works locally, no admin token needed     # mint a token
# call the built-in `mock` model — full pipeline (auth, scope, usage, cost, log), no real key:
curl -s localhost:8080/anthropic/v1/messages -H "x-api-key: pa_…" \
  -d '{"model":"mock","max_tokens":50,"messages":[{"role":"user","content":"hi"}]}'

Quickstart

1. Run the proxy (on a box you control — it holds the real keys):

pip install proxyagent
export ANTHROPIC_API_KEY=sk-ant-…      # and/or OPENAI_API_KEY=sk-…
proxyagent serve                        # prints an admin token + a dashboard at :8080

2. Mint a machine token (scoped + revocable):

proxyagent token new macbook-01 --scope "anthropic:claude-*"   # local: no admin token needed

3. Run any agent on any machine — no real key there:

PROXYAGENT_TOKEN=pa_… proxyagent run claude-code \
  --goal "build a SwiftUI todo app" --proxy https://proxy.you.com
# or:  proxyagent run codex --goal "fix the failing tests" --token pa_…

Or use any harness directly — just set the env and the proxy does the rest:

export ANTHROPIC_BASE_URL=https://proxy.you.com/anthropic
export ANTHROPIC_API_KEY=pa_…          # the machine token, not the real key
claude -p "ship it"

The dashboard

proxyagent serve ships a real dashboard at / (reveal the admin token with proxyagent admin-token):

  • Providers — a branded catalog of every supported provider; connect/disconnect with a key right from the UI, see which auth types each supports (api_key / oauth) and whether it's on via env or stored credentials.
  • Machine tokens — mint (scoped/TTL), list, revoke.
  • Model routing — add/remove model remaps (e.g. * → mock for offline).
  • Activity — live request log with usage + cost, and headline stats.

Proxied tools — the same trick, for tools

The proxy can also hold your tool keys and hand agents governed tools — so an agent gets web search (and custom tools) without ever holding the tool's credential.

export TAVILY_API_KEY=tvly-…                                   # web_search uses this; agents never see it
export PROXYAGENT_TOOLS='[{"name":"crm","url":"https://hooks.you.com/crm","headers":{"Authorization":"Bearer …"}}]'
# then send requests with header  x-proxyagent-tools: on  → tool defs are injected;
# the proxy executes calls to managed tools server-side (keys stay here).

Credentials, storage & cost

By default provider keys come from the environment and stay local. Or add them once and they're stored encrypted (proxy_agent_keys) — locally in SQLite, or in Postgres if you point at one. Either way the machine never sees them.

export PROXYAGENT_SECRET_KEY=                 # enables at-rest encryption (Fernet)
proxyagent provider add anthropic --key sk-ant-…          # stored, encrypted
proxyagent provider add openai --key sk-…  --kind api_key
# OAuth: store an access token →  proxyagent provider add anthropic --key <oauth-token> --kind oauth
proxyagent provider ls

# Postgres-backed (shared, multi-instance): tables proxy_agent_keys / _tokens / _calls
export PROXYAGENT_DATABASE_URL=postgresql://user:pass@host/db    # pip install 'proxyagent[postgres]'

Every call is traced in proxy_agent_calls with token usage, latency, and computed cost (per-model pricing, override via PROXYAGENT_PRICING). See it live:

proxyagent usage          # totals: requests · tokens · $ cost
proxyagent logs           # per-request trace incl. cost

Security model

  • Real keys never leave the proxy — read from env, never persisted, never logged, never returned.
  • Machine tokens are stored hashed (SHA-256); plaintext shown once. A stolen DB yields nothing usable.
  • Scoped (provider:model globs), expiring (TTL), revocable, rate-limited.
  • Constant-time token comparison; sensitive headers redacted from logs.
  • Admin API + dashboard gated by a separate admin token. Run it behind TLS.

SDK

import proxyagent

# host the proxy (embed in your own service):
app = proxyagent.create_app()              # ASGI app

# mint tokens programmatically:
admin = proxyagent.Admin("https://proxy.you.com", "pa_admin_…")
token = admin.mint("ci-runner", scope=["anthropic:claude-*"], ttl_seconds=3600)

# run a harness on this machine, no key here:
proxyagent.run("claude-code", goal="build the app",
               proxy="https://proxy.you.com", token=token)

Harnesses & auth modes

You run an agent harness, and each one can authenticate several ways. The proxy's job is to centralise all of them so the machine running the harness holds only a pa_ token:

Harness Provider Auth modes
Claude Code Anthropic API key · OAuth (subscription) · AWS Bedrock · Google Vertex
Codex OpenAI API key · OAuth (ChatGPT) · Azure
Gemini CLI Google API key · OAuth · Vertex

Connect each mode once in the dashboard's Harnesses tab. API-key mode is wired today; Bedrock / Vertex / OAuth-refresh (the cloud-credential paths enterprises actually use) are being built out — the proxy holds the AWS/GCP creds and signs upstream, so the machine needs none. The model providers below are the backends for model-agnostic harnesses (aider, Cline…).

Per-token budgets

Cap what any token can spend; once its summed cost crosses the cap, the proxy returns 402.

proxyagent token new ci --budget 5.00      # this token may spend at most $5

Supported providers

anthropic · openai · gemini · groq · openrouter · mistral · deepseek · xai · together — Anthropic uses its Messages API; the rest are OpenAI-compatible. Point a harness/agent at https://proxy.you.com/<provider>/v1 and it routes there. Add or override any endpoint with PROXYAGENT_<NAME>_ENDPOINT.

Model remap — rename or reroute models

Rewrite the requested model before forwarding — rename it, or reroute it to a totally different provider:

proxyagent alias set gpt-4o anthropic:claude-sonnet-4-5   # send "gpt-4o" calls to Claude
proxyagent alias set '*' mock                             # force EVERYTHING offline (no keys)
proxyagent alias ls

The '*' → mock trick is the offline harness unlock: point claude-code at the proxy, map everything to mock, and it runs end-to-end with zero keys and zero spend — perfect for local dev, demos, and CI.

Supported harnesses

claude-code, codex, and any custom command (--command "my-agent {goal}"). Adding one is a few lines — it just needs to respect *_BASE_URL.

License

Apache-2.0

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

proxyagent-0.5.1.tar.gz (33.1 kB view details)

Uploaded Source

Built Distribution

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

proxyagent-0.5.1-py3-none-any.whl (37.1 kB view details)

Uploaded Python 3

File details

Details for the file proxyagent-0.5.1.tar.gz.

File metadata

  • Download URL: proxyagent-0.5.1.tar.gz
  • Upload date:
  • Size: 33.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for proxyagent-0.5.1.tar.gz
Algorithm Hash digest
SHA256 2547e1af123a49e01526073fd39b2c2f229bbfe73ffec188ca61fc29170b406a
MD5 7f4ee58867c2530082e9543da988b7c7
BLAKE2b-256 0b6f1a1f06875a60c4e3a74514acc01d67ee6daca289f155c00ae26cc9b6b90e

See more details on using hashes here.

File details

Details for the file proxyagent-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: proxyagent-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 37.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for proxyagent-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 54f20fe41006cc6d979014d449721b54e1f2e1882e29dec9eca2e677c9d0a54c
MD5 314bea99444070ecf213fef964d15aab
BLAKE2b-256 c691ed51fcaa5fb89bad6c3b0c7e924ccc404cc8a397dc86044e095fc52e91f8

See more details on using hashes here.

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