agent-cli-proxy 0.1.0 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.2.1](https://github.com/INONONO66/agent-cli-proxy/compare/v0.2.0...v0.2.1) (2026-05-29)
6
+
7
+ ### Bug Fixes
8
+
9
+ - keep GitHub Release creation independent from npm publish failures
10
+ - package GitHub runtime assets after npm publish
11
+
12
+ ## [0.2.0](https://github.com/INONONO66/agent-cli-proxy/compare/v0.1.0...v0.2.0) (2026-05-29)
13
+
14
+ ### Features
15
+
16
+ - add separate local dashboard runtime and build output
17
+ - require managed proxy API keys through Authorization Bearer tokens
18
+ - attach release runtime tarballs to GitHub Releases
19
+
20
+ ### Bug Fixes
21
+
22
+ - disable CLIProxyAPI usage correlation after unsupported 404 responses
23
+ - keep admin APIs local-only by socket address
24
+
25
+ ### Documentation
26
+
27
+ - document GitHub Release based server installation
package/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
  [![npm version](https://img.shields.io/npm/v/agent-cli-proxy.svg)](https://www.npmjs.com/package/agent-cli-proxy)
5
5
  [![Bun](https://img.shields.io/badge/runtime-Bun-black)](https://bun.sh)
6
6
 
7
- AI API proxy with per-tool usage monitoring. Sits between AI coding tools (OpenCode, OpenClaw, Hermes) and upstream API providers, tracking usage per tool and per instance, computing token costs from live pricing data, and mapping CLIProxyAPI accounts to subscription plans for cost monitoring. Runs as a native Bun process. Self-hosted, no containers needed.
7
+ AI API proxy with per-tool usage monitoring. Sits between AI coding tools (OpenCode, OpenClaw, Hermes) and upstream API providers, tracking usage per tool and per instance, computing token costs from live pricing data, and correlating CLIProxyAPI accounts for cost attribution. Runs as a native Bun process. Self-hosted, no containers needed.
8
8
 
9
9
  ## Why this exists
10
10
 
11
- Most AI coding tools share a single upstream API key, making it impossible to know which tool or session is responsible for a given cost spike. agent-cli-proxy intercepts every request, identifies the originating tool from request headers, and records per-tool usage with accurate cost attribution from models.dev pricing data. It also maps CLIProxyAPI accounts to subscription plans so you can monitor spend against plan limits without any enforcement overhead.
11
+ Most AI coding tools share a single upstream API key, making it impossible to know which tool or session is responsible for a given cost spike. agent-cli-proxy forwards API requests, identifies the originating tool from request headers, and records LLM generation usage with accurate cost attribution from live pricing data. It also correlates CLIProxyAPI accounts to request rows so usage can be audited by upstream account.
12
12
 
13
13
  ## Install
14
14
 
@@ -27,14 +27,42 @@ agent-cli-proxy init
27
27
 
28
28
  ### From source
29
29
 
30
+ Requires Bun 1.3.0 or newer.
31
+
30
32
  ```bash
31
- git clone https://github.com/<owner>/agent-cli-proxy.git
33
+ git clone https://github.com/INONONO66/agent-cli-proxy.git
32
34
  cd agent-cli-proxy
33
35
  bun install
34
36
  bun run build
35
37
  bun run src/cli.ts init
36
38
  ```
37
39
 
40
+ ### Server install from GitHub Release
41
+
42
+ Install or update a server directly from the latest GitHub Release asset:
43
+
44
+ ```bash
45
+ curl -fsSL https://raw.githubusercontent.com/INONONO66/agent-cli-proxy/main/scripts/install-release.sh | bash
46
+ ```
47
+
48
+ Install a specific version and register the user service in one command:
49
+
50
+ ```bash
51
+ curl -fsSL https://raw.githubusercontent.com/INONONO66/agent-cli-proxy/main/scripts/install-release.sh | \
52
+ AGENT_CLI_PROXY_VERSION=v0.2.1 \
53
+ AGENT_CLI_PROXY_SERVICE=1 \
54
+ AGENT_CLI_PROXY_INIT=1 \
55
+ AGENT_CLI_PROXY_ENV=$HOME/.config/agent-cli-proxy/.env \
56
+ CLI_PROXY_API_URL=http://localhost:8317 \
57
+ bash
58
+ ```
59
+
60
+ The script requires Bun, downloads `agent-cli-proxy.tar.gz` from GitHub Releases,
61
+ installs the runtime under `~/.local/share/agent-cli-proxy/runtime`, and writes a
62
+ `~/.local/bin/agent-cli-proxy` wrapper. Set `AGENT_CLI_PROXY_INIT=1` to run
63
+ non-interactive initialization during install. Release tarball installs require
64
+ `v0.2.1` or newer because earlier tags do not include runtime assets.
65
+
38
66
  ## Quickstart
39
67
 
40
68
  1. **Initialize** — creates config, database, and prompts for optional features:
@@ -78,8 +106,8 @@ The installer creates OS-appropriate local paths by default:
78
106
 
79
107
  Optional features prompted during init:
80
108
 
81
- - Dashboard login (`DASHBOARD_PASSWORD_HASH`)
82
- - Admin API token (`ADMIN_API_KEY`) when exposing beyond loopback
109
+ - Local admin session login (`DASHBOARD_PASSWORD_HASH`)
110
+ - Admin API token (`ADMIN_API_KEY`) for local admin endpoints
83
111
  - CLIProxyAPI account correlation (`CLIPROXY_MGMT_KEY`)
84
112
  - SQLite/pricing cache paths
85
113
 
@@ -91,28 +119,77 @@ Provider API keys are intentionally **not** stored by this proxy. The proxy rout
91
119
  |----------|---------|-------------|
92
120
  | `PROXY_PORT` | `3100` | Proxy server port |
93
121
  | `PROXY_HOST` | `127.0.0.1` | Bind host. Keep loopback unless you add auth/network controls. |
94
- | `ADMIN_API_KEY` | | Required when `PROXY_HOST` is not loopback. Token for `/admin/*` endpoints. |
122
+ | `TRUST_PROXY_HEADERS` | `false` | Trust reverse-proxy headers such as `X-Forwarded-Proto`/Cloudflare visitor scheme for HTTPS-only decisions. Enable only behind a trusted proxy. |
123
+ | `ADMIN_API_KEY` | | Optional token for local-only `/admin/*` and `/metrics` endpoints. |
124
+ | `PROXY_REQUIRE_API_KEY` | `false` on loopback, `true` off loopback | Require a valid managed proxy key on `/v1/*` and `/api/*` requests, sent as either `Authorization: Bearer <proxy-key>` or `x-api-key: <proxy-key>`. Keep enabled for any externally reachable deployment. |
95
125
  | `CLI_PROXY_API_URL` | `http://localhost:8317` | Upstream CLIProxyAPI URL (required unless `PROXY_LOCAL_OK=1`) |
96
126
  | `CLI_PROXY_API_KEY` | `proxy` | Proxy auth key sent to CLIProxyAPI |
97
127
  | `CLAUDE_CODE_VERSION` | `2.1.87` | Claude Code version for bypass headers |
98
- | `DB_PATH` | `data/proxy.db` | SQLite database path |
99
- | `PRICING_CACHE_PATH` | `data/pricing-cache.json` | Runtime models.dev pricing cache |
128
+ | `DB_PATH` | `$XDG_DATA_HOME/agent-cli-proxy/proxy.db` or `~/.local/share/agent-cli-proxy/proxy.db` | SQLite database path. Use an absolute path outside repo/dist/runtime replacement directories. |
129
+ | `PRICING_CACHE_PATH` | `$XDG_DATA_HOME/agent-cli-proxy/pricing-cache.json` or `~/.local/share/agent-cli-proxy/pricing-cache.json` | Runtime models.dev pricing cache. Use an absolute path outside repo/dist/runtime replacement directories. |
100
130
  | `READY_PRICING_MAX_AGE_MS` | `86400000` | Maximum pricing cache age accepted by `/ready` (24h) |
101
131
  | `PRICING_REFRESH_INTERVAL_MS` | `21600000` | How often to refresh pricing from models.dev (6h) |
132
+ | `PRICING_OVERRIDES_JSON` | built-in overrides | Optional JSON object of model pricing overrides, keyed by model name. Values use models.dev-style `input`, `output`, `cache_read`, `cache_write`, and `reasoning` per-million-token prices. |
133
+ | `PRICING_ALIASES_JSON` | built-in aliases | Optional JSON object mapping model prefixes to pricing model names for local alias resolution. |
102
134
  | `COST_BACKFILL_INTERVAL_MS` | `1800000` | How often to backfill zero-cost request logs (30m) |
103
135
  | `COST_BACKFILL_LOOKBACK_MS` | `604800000` | How far back cost backfill looks (7d) |
104
- | `UPSTREAM_TIMEOUT_MS` | `300000` | Total upstream request timeout (5m) |
105
- | `UPSTREAM_CONNECT_TIMEOUT_MS` | `10000` | Upstream connection timeout (10s) |
106
- | `STALE_PENDING_MAX_AGE_MS` | `300000` | Age at which pending request rows are recovered on boot (5m) |
136
+ | `UPSTREAM_TIMEOUT_MS` | `0` | Total upstream request timeout. `0` disables the proxy-side timeout so CLIProxyAPI owns upstream timing. |
137
+ | `UPSTREAM_STREAM_FIRST_BYTE_TIMEOUT_MS` | `0` | First SSE chunk timeout for Claude `/v1/messages` streaming requests. `0` disables the proxy-side timeout. |
138
+ | `UPSTREAM_CONNECT_TIMEOUT_MS` | `0` | Upstream response-header timeout. `0` disables the proxy-side timeout so CLIProxyAPI can return its own result. |
139
+ | `UPSTREAM_MAX_RETRIES` | `2` | Retry attempts for retryable idempotent upstream failures |
140
+ | `UPSTREAM_CIRCUIT_BREAKER_OPEN_AFTER_FAILURES` | `5` | Consecutive upstream failures before a provider circuit opens |
141
+ | `UPSTREAM_CIRCUIT_BREAKER_HALF_OPEN_AFTER_MS` | `30000` | Recovery window before one half-open probe is allowed |
142
+ | `UPSTREAM_CIRCUIT_BREAKER_EVICT_AFTER_MS` | `300000` | Inactive closed provider breaker retention window |
143
+ | `MAX_REQUEST_BODY_BYTES` | `25000000` | Maximum request body size accepted for proxied POST requests (25MB) |
144
+ | `RATE_LIMIT_PER_CLIENT_PER_MIN` | `0` | Optional per `(tool, client_id)` proxy request limit per minute. `0` disables rate limiting. |
145
+ | `STALE_PENDING_MAX_AGE_MS` | `600000` | Age at which pending request rows are recovered on boot (10m) |
107
146
  | `QUOTA_REFRESH_INTERVAL_MS` | `300000` | How often to refresh CLIProxyAPI quota snapshots (5m) |
108
147
  | `QUOTA_REFRESH_TIMEOUT_MS` | `15000` | Timeout for provider quota refresh calls (15s) |
148
+ | `QUOTA_SNAPSHOT_RETENTION_DAYS` | `7` | Days of quota snapshots to retain |
109
149
  | `CLIENT_NAME_MAPPING` | | API key to display name mapping (e.g. `key1=alice,key2=bob`) |
110
150
  | `PROVIDERS_CONFIG_PATH` | | Optional JSON file for custom providers |
111
151
  | `PROVIDERS_JSON` | | Inline custom provider JSON; takes precedence over `PROVIDERS_CONFIG_PATH` |
112
- | `PLANS_JSON` | | Inline plans JSON; takes precedence over `PLANS_PATH` |
113
- | `PLANS_PATH` | | Path to a custom plans.json file |
114
- | `CLIPROXY_MGMT_KEY` | | Optional CLIProxyAPI management key for account correlation |
115
- | `CLIPROXY_AUTH_DIR` | | Optional CLIProxyAPI auth directory for subscription quota checks |
152
+ | `CLIPROXY_MGMT_KEY` | | Optional CLIProxyAPI management key for account correlation. Uses `/v0/management/usage-queue` on CLIProxyAPI v6.10+ and falls back to legacy `/v0/management/usage` for older servers. |
153
+ | `CLIPROXY_CORRELATION_LOOKBACK_MS` | `300000` | How far back the correlator fetches local request rows and upstream usage details (5m) |
154
+ | `CLIPROXY_CORRELATION_WINDOW_MS` | `30000` | Maximum timestamp difference allowed when matching a local row to upstream usage (30s) |
155
+ | `CLIPROXY_AUTH_DIR` | | Optional CLIProxyAPI auth directory for quota probes |
156
+ | `UPSTREAM_CIRCUIT_BREAKER_OPEN_AFTER_FAILURES` | `5` | Consecutive upstream failures before the circuit breaker opens |
157
+ | `UPSTREAM_CIRCUIT_BREAKER_HALF_OPEN_AFTER_MS` | `30000` | Delay before a half-open probe is allowed (30s) |
158
+ | `UPSTREAM_CIRCUIT_BREAKER_EVICT_AFTER_MS` | `300000` | Idle time before a healthy breaker is evicted (5m) |
159
+
160
+ ### Persistent config and data paths
161
+
162
+ Keep mutable files outside the deploy directory so `git pull`, rsync, package
163
+ replacement, or runtime bundle refreshes do not erase state:
164
+
165
+ - config/env: `~/.config/agent-cli-proxy/.env` for user installs, or
166
+ `/etc/agent-cli-proxy/agent-cli-proxy.env` for system installs
167
+ - SQLite DB and WAL/SHM: `~/.local/share/agent-cli-proxy/proxy.db` or
168
+ `/var/lib/agent-cli-proxy/proxy.db`
169
+ - pricing cache: `~/.local/share/agent-cli-proxy/pricing-cache.json` or
170
+ `/var/cache/agent-cli-proxy/pricing-cache.json`
171
+
172
+ `agent-cli-proxy init` writes absolute `DB_PATH` and `PRICING_CACHE_PATH`
173
+ values. Runtime defaults also use XDG data paths when those variables are
174
+ unset. Explicit relative paths still work for local development, but startup
175
+ emits configuration warnings because they are deploy-directory dependent.
176
+
177
+
178
+
179
+ ### Public proxy API keys
180
+
181
+ When the proxy binds to a non-loopback host, `PROXY_REQUIRE_API_KEY` defaults to
182
+ `true`. In that mode, every LLM proxy request under `/v1/*` and `/api/*` must
183
+ include a valid managed proxy key as either `Authorization: Bearer <proxy-key>`
184
+ or `x-api-key: <proxy-key>` (Anthropic-SDK style). `Authorization` takes
185
+ precedence when both are present. The legacy `x-proxy-key` header still does
186
+ not satisfy this application-level check. Non-loopback binds cannot disable
187
+ this requirement; keep `PROXY_HOST` on loopback for local development without
188
+ proxy client keys.
189
+
190
+ Create and manage client proxy keys from the local-only `/admin/api-keys` API.
191
+ These keys remain separate from `ADMIN_API_KEY` and from the upstream
192
+ `CLI_PROXY_API_KEY`.
116
193
 
117
194
  ## Custom Providers
118
195
 
@@ -142,43 +219,10 @@ Add OpenAI-compatible local or custom providers with JSON config. Select them pe
142
219
  }
143
220
  ```
144
221
 
145
- Provider fields: `id`, `type` (`openai-compatible` or `anthropic`), `paths`, `upstreamBaseUrl`, optional `upstreamPath`, `models`, `headers`, `auth` (`none`, `preserve`, `bearer`, `x-api-key`, or object with `env`/`value`/`header`), and `stripProviderField`.
222
+ Provider fields: `id`, `type` (`openai-compatible` or `anthropic`), `paths`, `upstreamBaseUrl`, optional `upstreamPath`, `models`, `headers`, `auth` (`none`, `preserve`, `bearer`, `x-api-key`, or object with `env`/`value`/`header`), and `stripProviderField`. Requests selected with `x-provider` or a JSON `provider` field are routed to the configured `upstreamBaseUrl` and `upstreamPath`; `stripProviderField: true` removes the selector before forwarding. Anthropic providers default `anthropic-version` to `2023-06-01` when the client omits it.
146
223
 
147
224
  Save this as a file and set `PROVIDERS_CONFIG_PATH`, or set `PROVIDERS_JSON` to the inline JSON string. Use `agent-cli-proxy providers init` to create a starter file at the default config path.
148
225
 
149
- ## Subscription Plans
150
-
151
- Plans map CLIProxyAPI accounts to subscription tiers for cost monitoring. This is **monitoring-only** — no request enforcement or quota blocking happens.
152
-
153
- ### plans.json format
154
-
155
- ```json
156
- {
157
- "plans": [
158
- {
159
- "code": "claude_pro",
160
- "display_name": "Anthropic Claude Pro",
161
- "monthly_price_usd": 20,
162
- "notes": "Conservative estimate — verify with vendor — last updated 2026-05"
163
- }
164
- ]
165
- }
166
- ```
167
-
168
- The proxy ships with a default `plans.json` covering common plans (Claude Pro/Max, ChatGPT Plus/Pro/Business, Kimi Pro, GLM Pro, local BYOK). Override with `PLANS_JSON` or `PLANS_PATH`.
169
-
170
- ### Plans CLI commands
171
-
172
- | Command | Description |
173
- |---------|-------------|
174
- | `agent-cli-proxy plans show` | Show loaded plans (human-readable) |
175
- | `agent-cli-proxy plans show --json` | Show loaded plans as JSON |
176
- | `agent-cli-proxy plans list` | List all plan codes and prices |
177
- | `agent-cli-proxy plans init` | Create a starter plans.json at the default config path |
178
- | `agent-cli-proxy plans path` | Print the active plans.json path |
179
- | `agent-cli-proxy plans bind <account> <code>` | Bind a CLIProxyAPI account to a plan code |
180
- | `agent-cli-proxy plans unbind <account>` | Remove a plan binding for an account |
181
-
182
226
  ## CLI Reference
183
227
 
184
228
  | Command | Description |
@@ -186,8 +230,9 @@ The proxy ships with a default `plans.json` covering common plans (Claude Pro/Ma
186
230
  | `agent-cli-proxy init` | Interactive config + DB setup |
187
231
  | `agent-cli-proxy init --non-interactive ...` | Non-interactive install (CI-friendly) |
188
232
  | `agent-cli-proxy db init` | Initialize or migrate the SQLite database |
233
+ | `agent-cli-proxy db backup --output PATH` | Create a consistent SQLite backup snapshot |
189
234
  | `agent-cli-proxy paths` | Print default install paths |
190
- | `agent-cli-proxy doctor` | Validate config, DB, plans, providers, pricing, upstream |
235
+ | `agent-cli-proxy doctor` | Validate config, DB, providers, pricing, upstream |
191
236
  | `agent-cli-proxy doctor --json` | Doctor output as JSON (for issue reports) |
192
237
  | `agent-cli-proxy service install` | Install user daemon (systemd/launchd) |
193
238
  | `agent-cli-proxy service start` | Start the daemon |
@@ -196,12 +241,6 @@ The proxy ships with a default `plans.json` covering common plans (Claude Pro/Ma
196
241
  | `agent-cli-proxy service status` | Show daemon status |
197
242
  | `agent-cli-proxy service logs` | Show daemon logs |
198
243
  | `agent-cli-proxy service logs --follow` | Stream daemon logs |
199
- | `agent-cli-proxy plans show` | Show loaded plans |
200
- | `agent-cli-proxy plans list` | List plan codes |
201
- | `agent-cli-proxy plans init` | Create starter plans.json |
202
- | `agent-cli-proxy plans path` | Print active plans.json path |
203
- | `agent-cli-proxy plans bind <account> <code>` | Bind account to plan |
204
- | `agent-cli-proxy plans unbind <account>` | Remove account binding |
205
244
  | `agent-cli-proxy providers show` | Show loaded provider config |
206
245
  | `agent-cli-proxy providers path` | Print active providers config path |
207
246
  | `agent-cli-proxy providers init` | Create starter providers.json |
@@ -211,39 +250,70 @@ The proxy ships with a default `plans.json` covering common plans (Claude Pro/Ma
211
250
 
212
251
  Prefer `--admin-token-env` and `--cliproxy-mgmt-key-env` for non-interactive installs so secrets do not appear in shell history or process arguments.
213
252
 
253
+ ## Operations
254
+
255
+ ### Database Backups
256
+
257
+ Use the CLI backup command to create a consistent SQLite snapshot while the daemon is running:
258
+
259
+ ```bash
260
+ agent-cli-proxy db backup --output /var/backups/agent-cli-proxy/proxy-$(date -u +%Y%m%dT%H%M%SZ).db
261
+ ```
262
+
263
+ The command reads `DB_PATH` from the default `.env`; pass `--env PATH` when using a non-default config file. It creates the output parent directory when needed and refuses to overwrite an existing backup. Run it from cron or a systemd timer and apply retention outside the command, for example by deleting backups older than your recovery window.
264
+
265
+ To restore, stop the daemon, copy the selected backup over `DB_PATH`, run `agent-cli-proxy db init` to apply any pending migrations for the installed version, then restart the daemon. To migrate to a new host, install the same or newer `agent-cli-proxy` version, copy the `.env` and backup file, set `DB_PATH` to the restored location, run `agent-cli-proxy db init`, and start the service.
266
+
214
267
  ## Admin Endpoints
215
268
 
216
- All `/admin/*` endpoints require `ADMIN_API_KEY` when the proxy is not bound to loopback.
269
+ `/admin/*` and `/metrics` are only available to loopback clients
270
+ (`127.0.0.1`, `::1`). When `ADMIN_API_KEY` is set, local callers must send
271
+ `x-admin-token: $ADMIN_API_KEY` or `Authorization: Bearer $ADMIN_API_KEY`.
272
+ The proxy no longer serves a bundled dashboard; build a dashboard as a separate
273
+ client that talks to these local admin APIs.
274
+
275
+ Usage day parameters and defaults are UTC dates.
217
276
 
218
277
  | Method | Path | Description |
219
278
  |--------|------|-------------|
220
279
  | `GET` | `/health` | Liveness probe (always 200 if process alive) |
221
280
  | `GET` | `/ready` | Readiness probe (DB, pricing, upstream); 503 when failing |
222
- | `GET` | `/metrics` | Prometheus-format metrics |
223
- | `GET` | `/admin/usage/today` | Today's usage summary |
281
+ | `GET` | `/metrics` | Prometheus-format metrics, including usage counters and low-cardinality latency histograms |
282
+ | `GET` | `/admin/usage/today` | Current UTC day usage summary |
224
283
  | `GET` | `/admin/usage/range?from=&to=` | Usage by date range |
225
284
  | `GET` | `/admin/usage/models?day=` | Model breakdown for a day |
226
285
  | `GET` | `/admin/usage/providers?day=` | Provider breakdown for a day |
227
286
  | `GET` | `/admin/usage/accounts?day=` | Per-account usage for a day |
228
287
  | `GET` | `/admin/usage/accounts/range?from=&to=` | Per-account usage over a range |
229
288
  | `GET` | `/admin/usage/accounts/summary?from=&to=` | Account summary (7-day default) |
289
+ | `GET` | `/admin/usage/trend?hours=` | Time-bucketed usage trend |
230
290
  | `GET` | `/admin/stats` | Total statistics |
231
291
  | `GET` | `/admin/logs` | Request logs (paginated) |
232
292
  | `GET` | `/admin/logs?tool=openclaw` | Filter logs by tool |
233
293
  | `GET` | `/admin/logs?client_id=openclaw-jongi` | Filter logs by instance |
234
294
  | `GET` | `/admin/logs/:id` | Single request log by ID |
295
+ | `GET` | `/admin/logs/:id/cost-audit` | Cost audit records for a request log |
235
296
  | `GET` | `/admin/quotas` | Latest stored quota snapshots |
236
297
  | `GET` | `/admin/quotas?refresh=true` | Refresh and return quota snapshots |
237
298
  | `GET` | `/admin/quotas/refresh` | Force refresh quota snapshots |
238
- | `GET` | `/admin/plans` | List all plans |
239
- | `GET` | `/admin/plans/cost-summary?month=YYYY-MM` | Monthly cost summary by account |
240
- | `GET` | `/admin/plans/account/:account` | Plan binding and recent usage for an account |
299
+ | `GET` | `/admin/quotas/probes` | Available quota probe definitions |
300
+ | `GET` | `/admin/quotas/history?hours=` | Time-bucketed quota snapshots |
301
+ | `GET` | `/admin/providers` | Loaded provider definitions and source info |
302
+ | `GET` | `/admin/pricing?model=&provider=` | Pricing match and cache freshness for a model |
303
+ | `GET` | `/admin/config` | Redacted runtime configuration summary |
304
+ | `GET` | `/admin/api-keys` | List managed proxy API keys |
305
+ | `POST` | `/admin/api-keys` | Create a managed proxy API key |
306
+ | `GET` | `/admin/breakers` | List all circuit breaker states |
307
+ | `GET` | `/admin/breakers/:providerId` | Single breaker state by provider |
308
+ | `POST` | `/admin/breakers/:providerId/reset` | Reset a breaker to closed state |
309
+
310
+ `/admin/logs` accepts `limit` from 1 to 200 and `offset` from 0 to 100000.
241
311
 
242
312
  ## Health and Readiness
243
313
 
244
314
  `/health` is a cheap liveness probe. It returns `200 {"status":"ok"}` as long as the process is alive, with no dependency checks.
245
315
 
246
- `/ready` is a readiness probe that checks the database, pricing cache freshness, upstream CLIProxyAPI, and supervisor loop state. It returns `200` when all checks pass and `503` when any critical dependency is failing.
316
+ `/ready` is a readiness probe that checks the database, pricing cache freshness, upstream CLIProxyAPI, and supervisor loop state. It returns `200` when all checks pass or only transient supervisor retries are in progress, and `503` when any critical dependency is failing.
247
317
 
248
318
  Sample `/ready` response:
249
319
 
@@ -254,7 +324,24 @@ Sample `/ready` response:
254
324
  "database": { "status": "pass", "responseTime": 3 },
255
325
  "pricing": { "status": "pass", "ageMs": 14400000 },
256
326
  "upstream": { "status": "pass", "responseTime": 42 },
257
- "supervisor": { "status": "pass", "loops": ["pricing-refresh", "cost-backfill"] }
327
+ "supervisor": {
328
+ "status": "warn",
329
+ "loops": ["pricing-refresh", "cost-backfill"],
330
+ "loopHealth": [
331
+ {
332
+ "name": "pricing-refresh",
333
+ "consecutiveFailures": 1,
334
+ "status": "warn",
335
+ "lastErrorAgeMs": 2500
336
+ },
337
+ {
338
+ "name": "cost-backfill",
339
+ "consecutiveFailures": 0,
340
+ "status": "pass",
341
+ "lastSuccessAgeMs": 60000
342
+ }
343
+ ]
344
+ }
258
345
  }
259
346
  }
260
347
  ```
@@ -272,9 +359,12 @@ Key event names:
272
359
  | `lifecycle.pre_logged` | Request row inserted before upstream call |
273
360
  | `lifecycle.finalized` | Request row updated after upstream response |
274
361
  | `lifecycle.aborted` | Request aborted before upstream response |
275
- | `upstream.error` | Upstream call failed (with error details) |
362
+ | `passthrough.upstream_headers` | Upstream response headers arrived; includes latency and status for pre-body diagnosis |
363
+ | `passthrough.stream_first_chunk` | First upstream SSE chunk arrived; includes latency for diagnosing Claude queueing |
364
+ | `upstream.error` | Upstream call failed (timeout, 5xx, network) |
365
+ | `upstream.breaker_reject` | Request rejected by open circuit breaker (not an upstream failure) |
366
+ | `upstream.breaker_reset` | Circuit breaker manually reset via admin endpoint |
276
367
  | `cost.guard` | Cost computation skipped or guarded |
277
- | `plans.unmapped` | CLIProxyAPI account has no plan binding |
278
368
  | `shutdown.drain` | Graceful shutdown draining in-flight requests |
279
369
  | `shutdown.complete` | Shutdown finalized cleanly |
280
370
 
@@ -288,7 +378,9 @@ Hermes ─┘
288
378
 
289
379
  Each tool is automatically identified by request headers and tracked separately. Multiple instances of the same tool are distinguished by `X-Agent-Name` header or session IDs.
290
380
 
291
- The request lifecycle: a `pending` row is inserted before the upstream call (pre-log), the upstream response streams to the client, and the row is finalized with tokens and cost after the stream completes. An optional correlator loop maps CLIProxyAPI accounts to request rows for subscription attribution. A cost backfill loop recomputes zero-cost rows when pricing data becomes available.
381
+ The request lifecycle for LLM generation calls: a `pending` row is inserted before the upstream call (pre-log), the upstream response streams to the client, and the row is finalized with tokens and cost after the stream completes. Non-LLM proxy calls are forwarded without request-log rows. ProviderTransform modules apply provider-specific header, body, response, and stream-line rewrites, while the provider registry selects built-in or custom providers. An optional correlator loop maps CLIProxyAPI accounts to request rows for account attribution. A cost backfill loop recomputes zero-cost rows when pricing data becomes available.
382
+
383
+ The correlator matches local rows to CLIProxyAPI usage by timestamp, model, and token totals. Keep the proxy host clock synchronized with CLIProxyAPI; sustained low match rates emit `correlator.low_match_rate`. If clocks can differ beyond the default 30 seconds, increase `CLIPROXY_CORRELATION_WINDOW_MS`.
292
384
 
293
385
  ### Tool Identification
294
386
 
@@ -303,10 +395,10 @@ The request lifecycle: a `pending` row is inserted before the upstream call (pre
303
395
  ```
304
396
  src/
305
397
  ├── config/ # Environment configuration and validation
306
- ├── identification/ # Plugin-based tool identification
307
398
  ├── provider/
308
- │ ├── anthropic/ # Claude bypass + request transform
309
- └── openai/ # OpenAI pass-through
399
+ │ ├── anthropic/ # Anthropic request/response helpers
400
+ ├── transforms/ # ProviderTransform registrations
401
+ │ └── registry.ts # Built-in and custom provider routing
310
402
  ├── server/ # HTTP handler, stream relay, usage logging
311
403
  ├── storage/ # SQLite repos, pricing, usage service
312
404
  ├── usage/ # Usage type definitions
@@ -315,7 +407,7 @@ src/
315
407
 
316
408
  ## Troubleshooting
317
409
 
318
- Run `agent-cli-proxy doctor` first. It validates configuration, opens the SQLite database, reports applied migrations, checks plans/providers configuration, inspects the pricing cache, probes `CLI_PROXY_API_URL/health`, and lists supervised loops. Use `--json` when attaching output to issues.
410
+ Run `agent-cli-proxy doctor` first. It validates configuration, opens the SQLite database, reports applied migrations, checks provider configuration, inspects the pricing cache, probes `CLI_PROXY_API_URL/health`, and lists supervised loops. Use `--json` when attaching output to issues.
319
411
 
320
412
  For daemon logs:
321
413
 
@@ -328,12 +420,11 @@ On Linux this proxies to `journalctl --user -u agent-cli-proxy.service -f`; on m
328
420
  **Common errors:**
329
421
 
330
422
  - `CLI_PROXY_API_URL is required` — set `CLI_PROXY_API_URL` in your `.env` or pass `PROXY_LOCAL_OK=1` to allow the local default.
331
- - `ADMIN_API_KEY is required when PROXY_HOST is not loopback` — set `ADMIN_API_KEY` before exposing the proxy beyond `127.0.0.1`.
332
- - Plans fallback warning in logs — `plans.json` failed to parse; the proxy fell back to bundled defaults. Run `agent-cli-proxy plans show` to inspect the active config.
423
+ - `PROXY_REQUIRE_API_KEY must be true when PROXY_HOST is not loopback` — public proxy binds require a managed proxy key (`Authorization: Bearer <proxy-key>` or `x-api-key: <proxy-key>`) for `/v1/*` and `/api/*` requests.
333
424
 
334
425
  ## Releasing
335
426
 
336
- For maintainers: run `bun run release-check` to verify the build and package contents before tagging. Push a `v*` tag and the `.github/workflows/release.yml` GitHub Actions workflow runs `bun publish --access public --tolerate-republish` against the npm registry using the `NPM_TOKEN` repository secret.
427
+ For maintainers: run `bun run release-check` to verify the build and package contents before tagging. Push a `v*` tag and the `.github/workflows/release.yml` GitHub Actions workflow runs `bun publish --access public --tolerate-republish` against the npm registry using the `NPM_TOKEN` repository secret, then creates a GitHub Release with `agent-cli-proxy.tar.gz` runtime assets for server installs.
337
428
 
338
429
  ## Contributing
339
430