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.15.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.
Lifecycle operations coordinate through a persistent <pidfile>.lock sidecar.
Do not remove this sidecar or edit the pidfile while daemon commands are active;
cleanup removes only the owned pidfile and leaves the sidecar in place.
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.
Configured safety nets at request admission
Surfaced request text in the direct Anthropic and legacy adapter paths now passes configured safety-net admission after primary pseudonymization and before provider I/O. Nets inspect the complete transformed surface with a manifest built from the actual session token ownership and restore boundaries. Token-contained reflags, including class disagreements, remain allowed; raw-gap or malformed suspects and net execution errors reject the request. No destructive clean fallback is used.
Compatibility: configured nets can now deny requests that previously reached the provider, including text preserved by primary policy when a net flags it. Admission adds inference on surfaced text and codec validation views, bypasses observer skip optimizations, and runs all registry backends selected across the locale chain. Registry resolution and inference errors fail closed. This can increase latency and inference cost. Primary Preserve/Redact actions and public legacy clean defaults are unchanged; admission does not certify their reversibility.
No installed net, a custom net skipped for locale coverage, or a detector miss remains a coverage limitation. A model is not required globally. Existing strict protection still requires its full primary and locale contract. Direct failures abandon staged mappings before commit/send. Legacy mappings are already live and remain so on failure; there is no whole-request rollback guarantee. Response restoration and response residual validation retain their existing contracts.