feat: admin dashboard, key management, rate limits, and cleanup#136
feat: admin dashboard, key management, rate limits, and cleanup#136realsc0t wants to merge 3 commits intorynfar:mainfrom
Conversation
|
Hey @realsc0t — thanks for putting this together, there's some genuinely useful thinking in here. I can see the vision: admin dashboard, key management, rate limits, OpenAI compat layer. Some of these are features I've been considering. That said, I'm not able to merge this as-is. A few things I need to work through with you: Breaking changes without migration path
Telemetry removal Test coverage Security concerns
What I'd suggest
Happy to discuss the approach — I think there's good stuff here that can land incrementally. What do you think? |
|
hey @rynfar |
|
Excellent, thank you! I am off to bed but I can get your revamp merged first thing in the morning. Thank you for working on that and helping improve the app! |
d04027f to
c955e65
Compare
|
the full description: feat: admin dashboard, key management, rate limits, and Meridian rebrandSummaryAdds a full-featured admin dashboard with JWT-based authentication, API key management with per-key rate limiting, OpenAI-compatible API layer, and Meridian rebrand — all backward compatible with existing deployments. Commits
Admin Dashboard (
|
| Endpoint | Auth |
|---|---|
/ |
Public |
/admin (HTML) |
No auth (login page) |
/admin/login |
No auth (POST master key) |
/admin/* (API) |
JWT |
/health |
JWT |
/v1/messages, /messages |
Managed key or ANTHROPIC_API_KEY |
/v1/models, /v1/chat/completions |
Managed key or ANTHROPIC_API_KEY |
Meridian Rebrand
All env vars accept both MERIDIAN_* (preferred) and CLAUDE_PROXY_* (backward compat):
| New | Legacy (still works) | Purpose |
|---|---|---|
MERIDIAN_MASTER_KEY |
CLAUDE_PROXY_MASTER_KEY |
Admin authentication |
MERIDIAN_PORT |
CLAUDE_PROXY_PORT |
Listen port |
MERIDIAN_HOST |
CLAUDE_PROXY_HOST |
Listen host |
MERIDIAN_PASSTHROUGH |
CLAUDE_PROXY_PASSTHROUGH |
Tool passthrough mode |
MERIDIAN_MAX_CONCURRENT |
CLAUDE_PROXY_MAX_CONCURRENT |
Max concurrent SDK sessions |
MERIDIAN_WORKDIR |
CLAUDE_PROXY_WORKDIR |
Working directory |
MERIDIAN_DEBUG |
CLAUDE_PROXY_DEBUG |
Debug logging |
MERIDIAN_KEYS_FILE |
CLAUDE_PROXY_KEYS_FILE |
Key store path |
MERIDIAN_SETTINGS_FILE |
CLAUDE_PROXY_SETTINGS_FILE |
Settings file path |
MERIDIAN_ADMIN_FILE |
CLAUDE_PROXY_ADMIN_FILE |
Admin config path |
MERIDIAN_SESSION_DIR |
CLAUDE_PROXY_SESSION_DIR |
Session storage dir |
MERIDIAN_MAX_SESSIONS |
CLAUDE_PROXY_MAX_SESSIONS |
Max cached sessions |
MERIDIAN_TELEMETRY_SIZE |
CLAUDE_PROXY_TELEMETRY_SIZE |
Telemetry buffer size |
MERIDIAN_IDLE_TIMEOUT_SECONDS |
CLAUDE_PROXY_IDLE_TIMEOUT_SECONDS |
Idle timeout |
User-facing strings rebranded to "Meridian". Internal paths (~/.claude-proxy/) unchanged.
New Features
OpenAI-compatible API:
POST /v1/chat/completions— streaming and non-streamingPOST /v1/completions— legacy text completionsPOST /v1/responses— Responses APIGET /v1/models/GET /v1/models/:id— model catalog- Full request/response transcoding (OpenAI ↔ Anthropic format)
Model catalog:
- 3 confirmed Claude Max models with correct context windows
claude-opus-4-6(1M context),claude-sonnet-4-6(1M),claude-haiku-4-5(200K)- Aliases still work for request resolution (e.g.,
opus,sonnet,haiku)
Per-key rate limits:
- 6-hour and weekly rolling window token limits
- Configurable per key via admin dashboard
- Enforced at middleware level (429 on exceed)
- Usage log entries auto-pruned after 7 days
Settings persistence:
~/.claude-proxy/settings.json— survives restarts- Max concurrent sessions, passthrough mode, global limits
- Editable via dashboard with immediate effect (no restart needed)
Port configuration:
ANTHROPIC_BASE_URLparsing (e.g.,http://localhost:4567)MERIDIAN_PORT/MERIDIAN_HOSToverrideANTHROPIC_BASE_URLCLAUDE_PROXY_PORT/CLAUDE_PROXY_HOSTstill work
Bug Fixes
- Remote proxy ENOENT crash: Windows clients send paths like
C:\Users\...as working directory. The SDK tried to spawn with that ascwdon Linux →ENOENT. Fixed by falling back to server CWD when client path doesn't exist locally. Client's real CWD is preserved in the system prompt for Claude to reference. - Streaming executable resolution:
claudeExecutablewas only lazily resolved inside the non-stream path. First streaming request would pass empty string to SDK. Moved resolution before the stream/non-stream branch. - Fixed landing page test: Updated for JSON-only root endpoint (removed HTML landing page dependency).
Performance
- Debounced
flush(): Key store writes batched with 100ms debounce viasetTimeout. CRUD operations useflushNow()(sync).recordUsage()(called on every request) uses debounced flush to avoid blocking the event loop. env()helper: Single function call per env var lookup withMERIDIAN_*→CLAUDE_PROXY_*fallback.
Test Coverage
63 new tests, 149 assertions, 0 failures:
| File | Tests | Coverage |
|---|---|---|
auth.test.ts |
7 | JWT generation, verification, expiry, master key validation, tamper detection |
admin-routes.test.ts |
8 | Login flow, JWT auth, invalid JWT rejection, models endpoint, settings endpoint |
key-store.test.ts |
14 | CRUD, persistence, enable/disable, reveal, rate limits, per-model tracking, usage windows |
env.test.ts |
5 | MERIDIAN_/CLAUDE_PROXY_ priority, fallback, undefined handling |
settings.test.ts |
5 | Defaults, update, clamping (1-100), passthrough toggle, global limits |
openai-compat.test.ts |
4 | Model catalog, context windows (1M/200K), required fields, aliases |
telemetry-routes.test.ts |
7 | Dashboard HTML, requests/summary/logs endpoints, filtering, limits |
telemetry-store.test.ts |
13 | Ring buffer, eviction, filtering, percentiles, error counting, model/mode breakdown |
c955e65 to
413440b
Compare
|
sonnet context fixed |
490bab5 to
a166f76
Compare
|
there is no sonnet[1m] even for max, I got max x20 and sonnet[1m] doesn't work. |
|
I was battling some other bugs - latest release shoud fix the sonnet issue. I am reviewing this pull request. I am sorry for the delay. |
3a5ec7b to
fda375f
Compare
|
Hey @realsc0t realsc0t thanks for putting this together — I can tell a lot of thought and work went into it, and I appreciate you wanting to help improve the project! A couple of things: The sonnet bug is already fixed. We merged subscription-aware model selection in #139 — the proxy now detects your subscription type via claude auth status and picks sonnet[1m] for Max subscribers and plain sonnet for team/pro. There's also On the PR itself — there's a lot of really interesting stuff in here (admin dashboard, key management, OpenAI compat, CWD fix, token usage tracking), but the scope is too broad for me to safely review and merge as a single PR. With 2600+ I'd love to consider these as smaller, focused PRs — for example:
For some of the bigger features (key management, auth overhaul, env var renaming), it'd be great to start with a feature request issue so we can discuss the direction before you invest time coding it — some of these might not align with If you can break these down into smaller PR's we can look at getting them merged! Thanks again for contributing — really do appreciate it! 🙏 |
|
@realsc0t dont want to discourage your help. I just have to start being more careful, I have a lot more people using this than I expected to when i published it. I want to move forward in a stable way to try and reduce any of the bug churn we have going on. Much of it is my own doing! Just trying to pace things a little better. |
|
@rynfar /sc0t |
fda375f to
e9b4430
Compare
I totally get it, I may start cherry picking some of your changes and bringing them in. I do want the admin panel with better logging i love it. I also understand the need for auth so I want to get that resolved quickly also. I am happy to take smaller prs, but i will also be mindful of the need and see if i can move some of these long with your ideas as a great starting point. Thank you! |
- Remove PROXY_PORT/CLAUDE_PROXY_PORT, parse port from ANTHROPIC_BASE_URL - Remove ANTHROPIC_API_KEY auth, use managed keys only - Add admin dashboard with master key auth (CLAUDE_PROXY_MASTER_KEY) - Add API key management (create, delete, enable/disable, per-key usage) - Add per-model token tracking per key - Add per-key rate limits (6h and weekly windows) with enforcement - Add configurable settings (max concurrent, passthrough mode, global limits) - Fix model catalog: 1M context for opus/sonnet, 200K for haiku - Add OpenAI-compatible API layer (/v1/chat/completions, /v1/models) - Remove telemetry module (replaced by persistent admin stats) - Clean up startup message
- Restore telemetry module under /admin/telemetry (protected by master key) - Add telemetry button to admin dashboard - Hash API keys at rest (SHA-256) — plaintext never stored on disk - Auto-migrate existing plaintext keys to hashed on first load - Remove reveal endpoint (hashed keys can't be revealed) - Mask master key in startup logs (show first 4 chars only) - Debounce flush() to avoid blocking event loop on rapid writes - Restore diagnosticLog calls in lineage.ts and telemetryStore.record() in server.ts
- Restore CLAUDE_PROXY_PORT/CLAUDE_PROXY_HOST (override ANTHROPIC_BASE_URL) - Make auth opt-in: only enforced when CLAUDE_PROXY_MASTER_KEY is set - Restore ANTHROPIC_API_KEY as static key auth (backward compatible) - Without CLAUDE_PROXY_MASTER_KEY, proxy runs in open-access mode - Restore telemetry test files - Add KeyStore tests: CRUD, hashing, rate limits, per-model tracking (12 tests) - Add admin routes tests: auth middleware, models, settings (7 tests) - Add OpenAI compat tests: model catalog, context windows, settings (4 tests)
e9b4430 to
82c8c90
Compare
feat: admin dashboard, key management, rate limits, and cleanup
Changes
Admin Dashboard (
/admin)Auth Overhaul
ANTHROPIC_API_KEYas auth method — managed keys only/admin/*protected byCLAUDE_PROXY_MASTER_KEY/healthprotected byCLAUDE_PROXY_MASTER_KEY/v1/messages,/v1/models, etc.) require managed API key/remains publicPort Configuration
ANTHROPIC_BASE_URL(e.g.,http://localhost:4567)Model Catalog
[1m]suffix), 200K for haikuRemote Proxy Fix
ENOENTcrash when remote clients (e.g., Windows) send working directories that don't exist on the Linux proxy servercwdnow falls back to server defaults when client CWD doesn't exist locallyCleanup
ANTHROPIC_BASE_URLandCLAUDE_PROXY_MASTER_KEYplease merge URGENTLY before any change.
/sc0t