umans-gate
v0.6.2
Published
LLM capture proxy with Anthropic cache_control TTL stamping, vision handoff, concurrency gating, rate limiting, and a live inspection dashboard
Downloads
4,052
Maintainers
Readme
umans-gate: stop guessing what your harness sends upstream
umans-gate is a local capture proxy for LLM APIs that intercepts Anthropic and OpenAI-compatible traffic, stores every request and response in a SQLite ring buffer, and serves a live inspection dashboard over WebSocket. Run one command; point your agent harness at it; observe every byte on the wire.
Personal-use project, MIT-licensed, maintained by codegiveness. Not affiliated with, endorsed by, or an official product of Umans AI. Last updated: 2026-07-31 · Version 0.6.1.
Author: codegiveness, independent developer building LLM tooling and observability infrastructure. Source code published under MIT for transparency. No commercial support tier.
Setup in 30 seconds.
npm install -g umans-gate && umans-gate service installThis installs the proxy as a background service — it auto-starts on
boot, survives terminal close, and auto-restarts on crash. The proxy
listens on http://localhost:1945. The dashboard is served at
http://localhost:1945/dashboard/. Point any Anthropic or
OpenAI-compatible harness at the proxy URL. Every request and response
is captured to SQLite.
What is umans-gate?
umans-gate is a local LLM API capture proxy that sits between an agent harness and the upstream LLM provider, stores every request and response in a SQLite ring buffer, and exposes a React dashboard with live WebSocket updates for inspecting traffic, cache behavior, and usage economics. It runs on Bun, requires no client-side code changes, and captures Anthropic and OpenAI-compatible endpoints in a single process.
Who should use umans-gate?
- umans.ai users who need visibility into API traffic, cache control TTL behavior, and per-request token economics.
- Agent harness users who must inspect and debug what their harness sends upstream: stamp pipeline output, thinking blocks, vision handoff.
- Developers integrating Anthropic or OpenAI-compatible APIs who need traffic capture, concurrency gating, and rate-limit validation in one local tool.
Features
| Feature | Description |
|---------|-------------|
| Capture proxy | Intercepts LLM API traffic (Anthropic + OpenAI-compatible); stores in SQLite with optional zstd compression |
| Stamp pipeline | Applies TTL, top_k, max_tokens, thinking, output_config, context_management, temperature stamps. Two toggles (Anthropic / OpenAI). |
| Vision handoff | Replaces image blocks with text descriptions from a vision model; cached 7 days with persistent SQLite storage |
| Concurrency gate | Semaphore + circuit breaker with intention-based reservations; hard cap and soft limit auto-sized from /v1/usage; queue timeout |
| Rate limiting | Two gates: an upstream snapshot gate that rejects at hardCap - request_rate_margin based on the unweighted usage.requests_in_window, plus an optional local sliding-window weighted limiter (fallback) |
| Connection warmer | Periodic /v1/models pings keep TLS warm; skips when real traffic occurred recently |
| Usage tracking | Fetches /v1/usage to size concurrency, detect rate-boxing, manage priority demotion |
| Live inspector | React + shadcn/ui dashboard with WebSocket live updates |
| SSE rendering | Streaming responses captured and rendered with expandable event previews |
| Ring buffer storage | Last N captures (default 200) in WAL-mode SQLite |
| Write-behind queue | Batched DB writes to minimize blocking during streaming |
| Hop-by-hop header stripping | Correct HTTP proxy behavior per RFC 7230 |
| Protocol flexibility | Upstream HTTP/1.1 (default) or HTTP/2 |
Important notes
- The proxy modifies your requests. Stamping is on by default
(
STAMP_CLAUDE_CODE_ENABLEDandSTAMP_REASONING_EFFORT_ENABLEDboth default totrue), so the proxy rewrites request bodies before forwarding upstream. The stamped body is what gets sent upstream AND captured. The proxy also forcesaccept-encoding: identityand stripscontent-encodingunconditionally. Toggle stamping off in the Config tab if you need a clean passthrough. - Vision strategy and non-Claude Code harnesses. Vision handoff
defaults to
VISION_STRATEGY=never, so images pass through untouched unless you opt in.catalogmeans a cache miss halts the request, calls When reenabled,catalogmeans a cache miss halts the request, calls the vision model to describe the image, rewrites the body with the text description, then forwards — so non-vision models receive text they can process. Subsequent requests for the same image hit the cache and skip the vision call. Do NOT configure the model as vision-capable on the harness side (except Claude Code). - Upstream target is hardcoded. Forwards to
https://api.code.umans.ai. OpenAI chat path, warmer path, and vision target are also hardcoded, not configurable. Listen address is hardcoded to127.0.0.1(loopback only). - Ring buffer overwrites old captures. Keeps only the last N (default
MAX_CAPTURES=200). Increase in config for longer history. - API key unlocks key features. Without
UMANS_API_KEY, the proxy still captures traffic, but/v1/usagepolling, concurrency gate sizing, rate-limit validation, and vision handoff stay disabled. - Service install recommended. Without
service install,umans-gateruns in the foreground and won't survive reboots or terminal close. Runumans-gate service installto register as a managed service. - Default concurrency and the hard cap toggle.
CONCURRENCY_HARD_CAPdefaults to16,CONCURRENCY_SOFT_LIMITto8. By default (USE_HARD_CAP=true), the effective limit is the hard cap. Both are auto-sized from/v1/usagewhenUMANS_API_KEYis set. Toggle in the dashboard Config tab. No restart needed.
Usage rights
Personal-use project with architecture modeled on production patterns but single-maintainer support. Source published under MIT for transparency and educational purposes. No guaranteed response time. No backward-compatibility commitment across versions; config shapes, flags, and APIs may change between releases without a deprecation cycle. No production support tier, no SLA. Security vulnerabilities are the one exception: see SECURITY.md for the 48-hour acknowledgment SLA on confirmed reports.
Not an official Umans product. Not affiliated with, endorsed by, or supported by Umans AI. All upstream service names, model names, and API endpoints belong to their respective owners.
How to install umans-gate
umans-gate ships as a pre-compiled npm binary and a standalone Bun/TypeScript source. The npm path requires no prerequisites; the Bun path requires Bun ≥ 1.1.0.
npm (recommended):
npm install -g umans-gate && umans-gate service installThe service install step registers umans-gate as a background service —
it auto-starts on boot and survives terminal close. If you skip it,
umans-gate runs in the foreground and dies when you close your terminal.
npx (temporary, no install):
npx umans-gate⚠️
npxruns a temporary instance that dies when you close the terminal. Don't use it for regular use — install withnpm install -gandservice installinstead.
Bun (for developers):
git clone https://github.com/codegiveness/umans-gate.git
cd umans-gate && bun install && bun src/cli.tsNo prerequisites for npm/npx. The package bundles a pre-compiled binary. For development, Bun ≥ 1.1.0 is required.
Platform support
| OS | Arch | npm Package |
|----|------|-------------|
| macOS | arm64/x64 | umans-gate-darwin-{arm64,x64} |
| Linux | x64/arm64 | umans-gate-linux-{x64,arm64} |
| Windows | x64/arm64 | umans-gate-win32-{x64,arm64} |
How to use umans-gate
Point any Anthropic or OpenAI-compatible agent harness at the proxy URL (http://localhost:1945). Every request and response is captured to SQLite and visible in the live dashboard at /dashboard/.
Start the proxy:
umans-gate service install(installs as background service — auto-starts on boot, survives terminal close). Already installed? Start it withumans-gate service start.Point your harness to
http://localhost:1945:export ANTHROPIC_BASE_URL=http://localhost:1945 export OPENAI_BASE_URL=http://localhost:1945Open the dashboard at
http://localhost:1945/dashboard/Set your API key (optional but recommended):
export UMANS_API_KEY=your-key-here # Or edit config.json: umans-gate config show # Or use the dashboard Config tabEnables
/v1/usagepolling, concurrency gate sizing, rate-limit validation, and vision handoff.Secure the dashboard (optional):
export DASHBOARD_TOKEN=your-secret-token. When set, all/dashboard/api/*routes,/health, and/metricsrequireAuthorization: Bearer <token>. WebSocket requires?token=<token>. Includes brute-force protection.Make it survive reboots:
umans-gate service install(already done if you followed the install steps above; this is just for reference).
Updating
umans-gate update # self-update (npm global or standalone binary)
umans-gate update --check # check without installing
umans-gate uninstall # removes service, config, database, binaryThe updater detects install method and acts accordingly. If running as a
managed service, stops before update and restarts after. Pass --keep-config
to preserve config.json and the database.
Service persistence
umans-gate service install # register as managed service
umans-gate service install --force # overwrite existing definition
umans-gate service start|stop|restart|status|logs|uninstall| Platform | Service manager | Unit location |
|----------|----------------|---------------|
| Linux | systemd (user unit + linger) | ~/.config/systemd/user/umans-gate.service |
| macOS | launchd (LaunchAgent) | ~/Library/LaunchAgents/com.umans.gate.plist |
| Windows | Windows Service (via NSSM) | Registered with sc.exe |
The service uses Restart=always / KeepAlive=true and auto-starts on
boot. API keys set via env var are stored securely (separate
EnvironmentFile with chmod 600 on systemd, in the plist on launchd, in
the service registry on Windows). When running as a managed service, the
dashboard Restart button works automatically.
How configuration works
umans-gate loads configuration from a JSON file with environment variable overrides. On first run, loadConfig() writes defaults if the file does not exist; existing configs are never overwritten. All env vars have snake_case JSON equivalents. Precedence, highest to lowest: env vars > JSON config > built-in defaults.
Dashboard-first: Edit config via the Config tab at
http://localhost:1945/dashboard/. The dashboard validates, shows field descriptions, and can hot-reload or restart.
| OS | Path |
|----|------|
| Linux/macOS | $XDG_CONFIG_HOME/umans-gate/config.json or ~/.config/umans-gate/config.json |
| Windows | %APPDATA%/umans-gate/config.json |
Precedence (highest to lowest): env vars > JSON config > built-in defaults.
Key config fields
| Variable | Default | Description |
|---|---|---|
| PORT | 1945 | Listen port |
| MAX_CAPTURES | 200 | Ring buffer size |
| DB_PATH | ./umans-gate.db | SQLite database path |
| UPSTREAM_PROTOCOL | http1.1 | http1.1 or http2 |
| UPSTREAM_TIMEOUT_MS | 1800000 | Upstream fetch timeout (30 min) |
| STAMP_CLAUDE_CODE_ENABLED | true | Toggle Claude Code stamp bundle (Anthropic) |
| STAMP_REASONING_EFFORT_ENABLED | true | Toggle reasoning_effort stamping (OpenAI) |
| STAMP_MODEL_RULES | [] | Per-model thinking-shape rules table (ADR-0029, hot-reloadable) |
| UMANS_API_KEY | (empty) | Unlocks /v1/usage, gate sizing, rate-limit, vision |
| DASHBOARD_TOKEN | (empty) | Secures dashboard + /health + /metrics + WS |
| CONCURRENCY_HARD_CAP | 16 | Max concurrent upstream (auto from /v1/usage) |
| CONCURRENCY_SOFT_LIMIT | 8 | Soft limit (auto from /v1/usage) |
| USE_HARD_CAP | true | true = use hard cap; false = use soft limit |
| VISION_STRATEGY | never | never, catalog, or always |
| VISION_MODEL | umans-flash | Vision model for image description |
| BREAKER_THRESHOLD | 5 | Circuit breaker failure threshold |
| RATE_LIMIT_REQUESTS | 0 | 0 = auto, -1 = unlimited, N = explicit |
See AGENTS.md for the complete config field table.
Hot reload
The Config tab can save and hot-reload via
POST /dashboard/api/config/reload. Hot-reloadable: all fields except
those marked restartRequired (e.g. port, db_path, upstream_protocol,
vision_strategy, vision_model, warmer_*, umans_api_key,
dashboard_token). The full set of hot-reloadable fields is defined in
src/config/reload.ts (RELOAD_FIELDS). Fields marked restartRequired
require a server restart.
How the stamp pipeline works
When STAMP_CLAUDE_CODE_ENABLED is true, the proxy applies the following stamps to Anthropic requests before forwarding upstream. The stamped body is what gets sent upstream AND what gets captured. The inspector shows exactly what went to the API.
- TTL:
"1h"oncache_controlephemeral blocks top_k:20temperature:1.0max_tokens:131071forumans-glm*models,32767for othersthinking:{ "type": "adaptive" }as the overlay default; per-model shapes viaSTAMP_MODEL_RULES(ADR-0029)output_config: efforthighormaxcontext_management:clear_thinking
Per-model rules (STAMP_MODEL_RULES, ADR-0029): a config-driven rules
table that overrides the adaptive thinking shape per model family on both
Anthropic and OpenAI routes. Each rule matches a model name pattern (glob,
first-match-wins) and can set anthropic_thinking_shape,
openai_thinking_shape, openai_extra_body, and
openai_veto_reasoning_effort. Rules are independent of the master toggles
and hot-reloadable. See ADR-0029
for the full spec and target table.
For OpenAI-compatible requests, STAMP_REASONING_EFFORT_ENABLED injects
reasoning_effort, strips output_config and context_management, and
forces temperature: 1.0. The thinking field is controlled by
STAMP_MODEL_RULES (PerModelRuleStep), not by reasoning_effort
stamping.
How vision handoff works
The vision handoff replaces image blocks in requests with text descriptions generated by a vision model. This reduces token cost and enables text-only models to process image-bearing requests. Descriptions are cached for 7 days in persistent SQLite storage.
Vision handoff defaults to
never(2026-08). umans.ai discontinued its subscription plan; only the wallet mechanism remains, so a fresh install ships withVISION_STRATEGY=never(no image handling). The pipeline is fully configurable — setVISION_STRATEGYtocatalogoralwaysin the dashboard Config tab or via config.json/env to opt in. No existing workflow is affected: with the default, images pass through untouched.
Strategies (VISION_STRATEGY):
| Strategy | Behavior |
|----------|----------|
| never (default) | Never replace images; pass through untouched |
| catalog | Replace images only if the target model lacks vision capability |
| always | Always replace images with text descriptions |
Intent-aware prompting (VISION_INTENT_STRATEGY, default auto):
accepts off, slotted, crafted, or auto. When auto, a
deterministic triage function routes each request to one of four
strategies (generic, slotted, crafted, decomposed) based on
adjacent text, image count, and tool-result status. off forces
generic only. Vision calls are serialized by the concurrency gate
(default concurrency = 4). Descriptions are cached for 7 days in
persistent SQLite storage.
How the concurrency gate works
The concurrency gate regulates upstream parallelism using three mechanisms: a semaphore enforcing soft/hard limits, a circuit breaker for failure isolation, and intention-based reservations with a bounded queue.
- Semaphore: enforces a soft limit and a hard cap on concurrent
upstream requests. Both are auto-sized from
/v1/usagewhenUMANS_API_KEYis set. - Circuit breaker: opens after
BREAKER_THRESHOLD(default5) HTTP 429 responses withinBREAKER_WINDOW_MS(default 5 minutes), blocks traffic forBREAKER_COOLDOWN_MS(default 60 seconds), then half-opens to probe recovery. - Intention-based reservations + queue: main and vision lanes hold
reserved slots; excess requests enter a bounded queue
(
MAX_QUEUE_DEPTH, default 100) with a timeout (QUEUE_TIMEOUT_MS, default 180 seconds).
How rate limiting works
Requests are protected by two gates. The upstream snapshot gate is the
authoritative one: it compares the live, unweighted usage.requests_in_window
from /v1/usage against limits.requests.hard_cap - request_rate_margin
(default margin 50). When the window count reaches that threshold it rejects
locally with 503 rate_limit_exceeded + retry-after, so the request is never
forwarded upstream and the wallet never trips the upstream hard cap. This gate
is active regardless of the knobs below and cannot be disabled (the live
snapshot is the single source of truth).
The optional local weighted limiter is a sliding-window weighted counter
used as a fallback for bursts between /v1/usage polls. It is controlled by
RATE_LIMIT_REQUESTS and NEVER_LIMIT_REQUESTS:
| RATE_LIMIT_REQUESTS | Behavior |
|-----------------------|----------|
| 0 (default) | Auto-derived from /v1/usage |
| -1 | Disables the local weighted limiter (upstream gate stays active) |
| N (positive integer) | Explicit weighted sliding window of N requests |
NEVER_LIMIT_REQUESTS disables the local weighted limiter only; it has no
effect on the upstream snapshot gate. REQUEST_RATE_MARGIN (default 50)
controls how far below the hard cap the proxy rejects.
Programmatic API
import { createProxyServer } from "umans-gate";
const server = createProxyServer({
config: { port: 8080 },
});
// server.db : CaptureDB instance
// server.ws : WsBroadcaster instance
// server.queue : WriteQueue instance
// server.shutdown(): graceful shutdownDevelopment
bun run dev # start proxy server
bun run typecheck # TypeScript checking
bun run lint # Biome lint
bun run lint:fix # Biome lint + auto-fix
bun run test # server tests
bun run test:dashboard # dashboard tests (vitest + jsdom)
bun run test:all # server + dashboard tests
bun run build # build server (tsup) + dashboard (vite)FAQ
Is umans-gate free?
Yes. umans-gate is MIT-licensed and free to use, modify, and distribute. The npm package (npm install -g umans-gate) and standalone binaries are free. No paid tier, no feature gating. Source code is public on GitHub.
Does umans-gate work with Claude Code?
Yes. umans-gate intercepts Anthropic API traffic, which is what Claude Code uses. Point ANTHROPIC_BASE_URL at the proxy (http://localhost:1945) and every request is captured. The stamp pipeline (STAMP_CLAUDE_CODE_ENABLED=true) applies TTL, top_k, temperature, max_tokens, thinking, output_config, and context_management stamps to Anthropic requests.
Does umans-gate work with OpenAI-compatible APIs?
Yes. The proxy intercepts OpenAI-compatible traffic on /v1/chat/completions. With STAMP_REASONING_EFFORT_ENABLED=true, it injects reasoning_effort, strips output_config and context_management, and forces temperature: 1.0. The thinking field is controlled by STAMP_MODEL_RULES (per-model rules, ADR-0029), not by reasoning_effort stamping.
What is the difference between umans-gate and a regular HTTP proxy?
⚠️ Experimental: enabled by
stamp_claude_code_enabled(default: on)
A regular HTTP proxy forwards traffic. umans-gate captures every request/response pair to SQLite, stamps ttl onto cache_control ephemeral blocks, runs a vision handoff pipeline (image → text description), enforces concurrency limits with a circuit breaker, and serves a live React dashboard over WebSocket. It is purpose-built for LLM API traffic observation and optimization.
Does umans-gate modify my requests?
By default, the proxy applies minor body modifications: it strips oh-my-openagent's [Category+Skill Reminder] text blocks from Anthropic requests (EXPERIMENT_STRIP_OMO_REMINDER, default: on), and it always forces accept-encoding: identity and strips content-encoding for capture safety. Full stamping (STAMP_CLAUDE_CODE_ENABLED for Anthropic, STAMP_REASONING_EFFORT_ENABLED for OpenAI) is on by default — the proxy rewrites request bodies (TTL, thinking, max_tokens, etc.) before forwarding upstream, and the stamped body is what gets captured. Toggle any of these off in the Config tab for a clean passthrough.
What is the ring buffer and how many captures does it store?
The ring buffer is a SQLite table capped at MAX_CAPTURES (default 200). When the limit is reached, the oldest captures are evicted. Increase MAX_CAPTURES in config for longer history. Bodies are optionally compressed with zstd, and capture_body_max_bytes (default 10 MB) limits per-capture size.
Can I run umans-gate in production?
umans-gate is a personal-use project with no production support tier, no SLA, and no backward-compatibility commitment. It is designed for local development and debugging. Security vulnerabilities are the exception. See SECURITY.md for the 48-hour acknowledgment SLA.
How do I secure the dashboard?
Set DASHBOARD_TOKEN via env or config. When set, all /dashboard/api/* routes, /health, /metrics, and WebSocket connections require Authorization: Bearer <token> (or ?token=<token> for WS). Includes brute-force protection.
Does umans-gate support HTTP/2?
Yes, as an opt-in. Set UPSTREAM_PROTOCOL=http2 in config or env. HTTP/1.1 is the default because benchmarks show no measurable difference at typical LLM concurrency levels (4 concurrent SSE streams). See BENCHMARKS.md for details.
What is vision handoff and when should I use it?
Vision handoff replaces image blocks in requests with text descriptions generated by a vision model (default umans-flash). This reduces token cost and enables text-only models to process image-bearing requests. Descriptions are cached for 7 days. Vision handoff is currently disabled by default (VISION_STRATEGY=never) while umans.ai's subscription plan is unavailable; it will be reactivated when a new plan or a cheaper multimodal model is available. When enabled, use VISION_STRATEGY=always to intercept all images, catalog to intercept only when the target model lacks vision capability, or never to disable.
Documentation
Start here: Documentation Index: curated reading guide
Understand:
- Architecture: system design and data flow
- Proxy Modifications: proxy modification inventory
Operate:
- Operations: day-to-day ops: start/stop, upgrades, health, backup
- Troubleshooting: common issues
- Benchmarks: benchmark results
Develop:
- Contributing: how to contribute
- Security Policy: vulnerability reporting
- Changelog: version history
Design:
- Dashboard Design System: design tokens and components
License
MIT. See LICENSE. This project provides llms.txt for LLM discoverability.
