gaze-proxy
gaze-proxy is the feature-gated HTTP proxy runtime for LLM SDK base-URL swaps.
It preserves each provider's native wire shape and uses adapters only to locate
PII-bearing fields before calling the supplied gaze::Pipeline.
Cargo
[]
= "0.13.0"
Quickstart
Then point SDKs at the daemon:
The default config is written to ~/.config/gaze/proxy.toml and includes:
= "127.0.0.1:8787"
= "30m"
= "core"
[]
= "https://api.openai.com/"
[]
= "https://api.anthropic.com/"
[]
= "https://generativelanguage.googleapis.com/"
Locale
Recognizers that declare locales = [...] — postal.de, postal.us, the national phone
recognizers — only run when the active locale chain intersects that list. The proxy resolves
that chain once and uses it for both the primary surface pass and the outbound residual
re-scan, so the two can never disagree about what counts as PII.
gaze proxy has no --locale flag; the chain comes from the policy you pass:
= ["de-DE"]
With no policy the chain is ["global"] and locale-gated recognizers stay inert. Library
adopters set it explicitly, passing the same chain the pipeline was assembled under:
let core = new
.with_bundled_rulepack
.with_locale
.build?;
let config = new.with_locale_chain;
A locale chain always ends in global, so configuring one can only widen detection.
Providers
- OpenAI:
POST /v1/chat/completions,/v1/completions,/v1/responses - Anthropic:
POST /v1/messages - Gemini:
POST /v1beta/models/*:{generateContent,streamGenerateContent,countTokens}
Each adapter walks text, tool-call, tool-result, and function argument surfaces in that provider's native JSON. The proxy does not transcode requests.
Daemon Commands
Pidfiles live under the platform local-data directory, never /tmp. Stale
pidfiles are revalidated with process liveness checks and cleaned before start.
gaze proxy logs --follow is also available for local daemon inspection.
Security Notes
The strict Anthropic Messages profile rebuilds its outbound headers from a closed
allowlist: content-type, x-api-key, anthropic-version, and an optional,
explicitly allowlisted anthropic-beta. Unconfigured Authorization, bearer
credentials, cookies, and unknown SDK headers are accepted at ingress and
dropped. If an embedding host configures Authorization as local listener
authentication, it is a singleton consumed only by the trusted principal
resolver and is still never forwarded.
AnthropicAdapter::new is an ephemeral, single-request profile and rejects
x-gaze-session-id. Session continuity is an explicit builder/configuration
choice and then requires that header with a canonical lowercase UUIDv4 value.
The SDK base URL is the proxy root, while the only direct route is exactly
POST /v1/messages.
The listener does not become an access-control boundary merely because provider credentials pass through it. Bind to loopback unless an explicit trusted principal resolver protects a non-loopback listener. See the strict Anthropic Messages contract for the complete wire, proof, inspection, migration, and manual SDK-test contract.