agentcap-cli 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,304 @@
1
+ Metadata-Version: 2.5
2
+ Name: agentcap-cli
3
+ Version: 0.1.0
4
+ Summary: API-key spend guard for unattended Codex CLI and Gemini CLI runs: hard per-run cap, kills the process at the limit.
5
+ Project-URL: Homepage, https://agentcap.launchbench.studio
6
+ Project-URL: Repository, https://github.com/Blitz00X/agentcap
7
+ Project-URL: Issues, https://github.com/Blitz00X/agentcap/issues
8
+ Author-email: Kutay Karahan <kutaykarahan6@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-agents,budget,codex-cli,cost-control,gemini-cli,llm,proxy,spend-cap
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: POSIX
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: httpx>=0.27
23
+ Requires-Dist: starlette>=0.37
24
+ Requires-Dist: uvicorn>=0.30
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
27
+ Requires-Dist: pytest>=8; extra == 'dev'
28
+ Requires-Dist: respx>=0.21; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # AgentCap
32
+
33
+ **The API-key guard for unattended Codex CLI and Gemini CLI runs.** AgentCap runs
34
+ the CLI behind a local proxy on `127.0.0.1`, caps spend for the run, and when the
35
+ budget is gone it kills the local process and tells you why. No dashboard, no
36
+ account, no code changes for tools that honour a base-URL environment variable.
37
+
38
+ It meters API-key traffic: `POST /v1/responses` and `/v1/chat/completions`
39
+ (Codex CLI uses the Responses API) plus Gemini `generateContent` /
40
+ `streamGenerateContent`, by setting `OPENAI_BASE_URL` and
41
+ `GOOGLE_GEMINI_BASE_URL` for the child. ChatGPT or Google sign-in
42
+ (OAuth/subscription) traffic is not metered.
43
+
44
+ ## What it is
45
+
46
+ AgentCap is a small, local, serverless spend-cap proxy. You give it a command
47
+ and a cap:
48
+
49
+ ```bash
50
+ agentcap run --cap 2 -- codex exec "fix the failing tests"
51
+ ```
52
+
53
+ Everything the child sends to OpenAI or Gemini is routed through a proxy on
54
+ `127.0.0.1`. AgentCap reserves the worst-case cost of each request before it is
55
+ forwarded, settles the real usage afterwards, and terminates the agent's process
56
+ group if the cap would be exceeded.
57
+
58
+ ## Install
59
+
60
+ The package is published on PyPI as `agentcap-cli` (the name `agentcap` is
61
+ taken), but the command it installs is still `agentcap`.
62
+
63
+ ```bash
64
+ # install the command globally
65
+ pipx install agentcap-cli
66
+
67
+ # or into the current environment
68
+ pip install agentcap-cli
69
+ ```
70
+
71
+ From a checkout:
72
+
73
+ ```bash
74
+ uv venv .venv
75
+ uv pip install -e .
76
+
77
+ # or install this checkout as the global command
78
+ pipx install .
79
+ ```
80
+
81
+ ## Quickstart
82
+
83
+ ```bash
84
+ # Codex CLI under a $2 cap (API-key mode: uses OPENAI_API_KEY)
85
+ agentcap run --cap 2 -- codex exec "fix the failing tests"
86
+
87
+ # Gemini CLI under a $2 cap (API-key mode: uses GEMINI_API_KEY)
88
+ agentcap run --cap 2 -- gemini -p "refactor utils.py"
89
+
90
+ # Run your own Python agent (it must honour OPENAI_BASE_URL)
91
+ agentcap run --cap 1 -- python my_agent.py
92
+
93
+ # Keep a proxy open for several terminals
94
+ agentcap serve --port 8787 --cap 5
95
+
96
+ # Inspect spend
97
+ agentcap status --port 8787
98
+ agentcap status --db
99
+
100
+ # Inspect the bundled price table
101
+ agentcap pricing
102
+ agentcap pricing google/gemini-4-argon
103
+ ```
104
+
105
+ Uses your API key (`OPENAI_API_KEY` / `GEMINI_API_KEY`). ChatGPT or Google
106
+ sign-in (OAuth/subscription) traffic is not metered.
107
+
108
+ `agentcap run` accepts `--cap` (default `$5`, or `$AGENTCAP_CAP`),
109
+ `--hour-cap` / `--day-cap` (Pro), `--allow-unmetered`, `--no-clamp`, `--port`
110
+ and `--quiet`.
111
+
112
+ ## Try it without an API key
113
+
114
+ A local fake upstream is bundled for testing metering and clamping offline.
115
+
116
+ ```bash
117
+ # Terminal 1: a fake Gemini/OpenAI endpoint on loopback only
118
+ python -m agentcap.devtools.fake_upstream --port 9000
119
+
120
+ # Terminal 2: run a child against it (no API key needed)
121
+ AGENTCAP_GEMINI_UPSTREAM=http://127.0.0.1:9000 \
122
+ agentcap run --cap 0.05 -- python - <<'PY'
123
+ import os, httpx
124
+
125
+ base = os.environ["GOOGLE_GEMINI_BASE_URL"]
126
+ url = base + "/v1beta/models/gemini-4-argon:generateContent"
127
+ r = httpx.post(url, json={"contents": [{"parts": [{"text": "hi"}]}]})
128
+ print(r.status_code, "output limit:", r.headers.get("x-fake-output-limit"))
129
+ PY
130
+ ```
131
+
132
+ The fake returns realistic prompt tokens (`ceil(text characters / 4)`) and
133
+ `min(output limit, 2000)` output tokens, so the run has a real cost. The
134
+ `x-fake-output-limit` response header echoes the limit the fake actually
135
+ received (`none` if the request had none): with a 5-cent cap the number should
136
+ be below the model's 65536-token default, proving AgentCap clamped it. Use
137
+ `AGENTCAP_OPENAI_UPSTREAM` for OpenAI paths.
138
+
139
+ Overrides must be `https://`, or `http://` on `127.0.0.1`, `localhost` or
140
+ `::1`; anything else is refused with exit code 2. A yellow one-line notice
141
+ shows the active override with userinfo and query strings stripped.
142
+
143
+ ## How it works
144
+
145
+ 1. `agentcap run` starts the proxy on a random free port, bound **only** to
146
+ `127.0.0.1`, and waits for `/_agentcap/status`.
147
+ 2. The child process is started in its own process group with:
148
+
149
+ ```text
150
+ OPENAI_BASE_URL=http://127.0.0.1:PORT/openai/v1
151
+ GOOGLE_GEMINI_BASE_URL=http://127.0.0.1:PORT/gemini
152
+ GEMINI_API_BASE_URL=http://127.0.0.1:PORT/gemini
153
+ AGENTCAP_RUN_ID=...
154
+ AGENTCAP_PROXY=http://127.0.0.1:PORT
155
+ ```
156
+
157
+ 3. Before forwarding a request, the proxy estimates the prompt size and the
158
+ maximum output size, then atomically reserves that worst-case USD amount in
159
+ a local SQLite ledger. The input estimate is padded by a conservative
160
+ `input_safety_factor` (1.25 by default) to cover system prompts, tool
161
+ schemas, images and tokenizer differences that the local estimate cannot
162
+ see. Concurrent requests cannot jointly overshoot the cap.
163
+ 4. After the upstream responds, the real usage is parsed and the reservation is
164
+ settled to the actual cost (rounded up to the micro-dollar). Settlement uses
165
+ the provider's reported tokens, never the padded estimate. If the provider
166
+ bills more input tokens than estimated, that one settlement can exceed its
167
+ reservation; AgentCap emits an `overshoot` alert and the run's spend may end
168
+ slightly above the cap.
169
+ 5. If the worst case does not fit the remaining budget but the prompt itself
170
+ does, the proxy **clamps the output limit** to exactly what fits (at least
171
+ `256` tokens by default) and reserves only that amount. The agent keeps
172
+ running instead of dying on the first request; real usage still settles the
173
+ reservation. Clamping is on by default and can be disabled with
174
+ `--no-clamp`.
175
+ 6. If even a minimal clamped request cannot fit, the request is blocked and the
176
+ whole child process group is terminated (`SIGTERM`, then `SIGKILL` after
177
+ 5s). `agentcap run` exits with code `3`. A detected loop exits with `4`.
178
+ The kill and its red alert fire at most once per run; later rejected
179
+ requests just receive `429` responses.
180
+ 7. Unknown models and unparseable bodies are rejected (fail-closed); the request
181
+ is never forwarded unmetered.
182
+
183
+ The proxy makes only two kinds of request-body change: it adds
184
+ `stream_options.include_usage` to OpenAI Chat Completions streams so final
185
+ usage is available, and (unless `--no-clamp` is given) it lowers the request's
186
+ output limit when the worst-case reservation would cross the remaining budget.
187
+ For OpenAI that is `max_completion_tokens` (or the legacy `max_tokens` if the
188
+ body already used it) or `max_output_tokens` for the Responses API; for Gemini
189
+ it is `generationConfig.maxOutputTokens`. An existing smaller limit is never
190
+ raised. Everything else is forwarded byte-for-byte, including credentials.
191
+
192
+ Reasoning/thinking tokens are billed as output and count against the same
193
+ output limit, so a clamp also caps them.
194
+
195
+ ## Supported
196
+
197
+ | Provider | Endpoints |
198
+ | --- | --- |
199
+ | OpenAI | `POST /v1/chat/completions`, `/v1/responses`, `/v1/completions`, `/v1/embeddings` |
200
+ | Gemini | `generateContent`, `streamGenerateContent` (other Gemini endpoints pass through) |
201
+
202
+ Token counting (`countTokens`) and `GET` requests are free passthroughs.
203
+ Request bodies are billed at price-book rates; embeddings are input-only.
204
+
205
+ ## Limitations
206
+
207
+ - Only tools that honour `OPENAI_BASE_URL` / `GOOGLE_GEMINI_BASE_URL` (and send
208
+ API keys) can be metered. OAuth or subscription logins are **not** metered.
209
+ - Prices are a local table, not a live feed. Check them with
210
+ `agentcap pricing`; override any entry in
211
+ `~/.config/agentcap/pricing.json` (or `$AGENTCAP_PRICING_FILE`).
212
+ - The proxy rewrites a request only to add `stream_options.include_usage` to
213
+ OpenAI chat streams and, unless `--no-clamp` is set, to lower its output
214
+ limit to what the remaining budget can afford. Prompts are never changed.
215
+ - Estimates are deliberately conservative, so a reservation can be larger than
216
+ the eventual cost. The cap is enforced before each request with a worst-case
217
+ reservation, and concurrent requests cannot jointly overshoot it. This is not
218
+ a mathematical guarantee: if a provider bills more input tokens than
219
+ estimated (for example server-side system prompts, tool schemas, images or
220
+ tokenizer differences), the final spend can exceed the cap by at most that
221
+ one request's estimation error. AgentCap emits an `overshoot` alert when a
222
+ settlement exceeds its reservation.
223
+ - The ledger lives at `~/.local/share/agentcap/ledger.sqlite3`
224
+ (override with `$AGENTCAP_DB`).
225
+
226
+ ## Privacy
227
+
228
+ AgentCap stores **no prompts, response contents, API keys or Authorization
229
+ headers** — not in the ledger, not in logs, not in alerts. Only token counts,
230
+ costs, model names, timestamps and request hashes are recorded. Nothing leaves
231
+ your machine except your own upstream API calls — and, for Pro users only, the
232
+ license check described below.
233
+
234
+ **Pro license checks:** activating a Pro key (and the periodic re-check) sends
235
+ only the license key, the Polar organization id and an anonymous machine
236
+ fingerprint hash (SHA-256; it contains no hostname and no username) to Polar's
237
+ public license API at `api.polar.sh`. Free users make no license requests at
238
+ all.
239
+
240
+ ## Free vs Pro
241
+
242
+ | Capability | Free | Pro |
243
+ | --- | --- | --- |
244
+ | Per-run USD cap with worst-case reservation | ✅ | ✅ |
245
+ | Output clamping | ✅ | ✅ |
246
+ | Kills the local process at the cap | ✅ | ✅ |
247
+ | Terminal alert with the reason | ✅ | ✅ |
248
+ | Loop breaker (exit code 4) | — | ✅ |
249
+ | Webhook alerts (`AGENTCAP_WEBHOOK_URL`) | — | ✅ |
250
+ | Telegram alerts (`AGENTCAP_TELEGRAM_BOT_TOKEN`, `AGENTCAP_TELEGRAM_CHAT_ID`) | — | ✅ |
251
+ | Hourly / daily caps | — | ✅ |
252
+
253
+ Free is **$0 forever**: the basic hard cap — a per-run USD cap with a
254
+ worst-case reservation, output clamping, the run killed at the cap, and
255
+ terminal alerts — with no account required.
256
+
257
+ Pro is **$12 one-time** — not a subscription — and is centred on the **loop
258
+ breaker**: loop detection that stops a stuck agent and exits with code `4`.
259
+ It also adds **alerts** over a webhook and Telegram, plus hourly / daily caps as
260
+ an extra, and updates for the 0.x line.
261
+
262
+ [Buy AgentCap Pro — $12](https://buy.polar.sh/polar_cl_qagsvUdwQ0dRvaW7X5ynEJg5md27pEctIRAr40MBeLi)
263
+
264
+ After purchase you receive a license key by email (via Polar). Activate it with
265
+ `agentcap license activate <KEY>`; `agentcap license deactivate` removes it from
266
+ this machine.
267
+
268
+ ## How it compares
269
+
270
+ | Tool | What it does and how it enforces a cap |
271
+ | --- | --- |
272
+ | RelayPlane | [relayplane.com](https://relayplane.com): free, MIT-licensed local proxy with daily/hourly/per-request/per-run caps, routing and a kill switch. In its source (as of early Oct 2026) we found no inbound OpenAI Responses API (`/v1/responses`) route and no Gemini-native `generateContent` route, and on budget breach it blocks or warns at the proxy rather than stopping your agent's process. A good choice for Anthropic/OpenAI chat traffic and broader routing. |
273
+ | LoopGuard | [tryloopguard.com](https://tryloopguard.com): free MIT CLI that hooks into Claude Code, Codex CLI and Cursor (no proxy, works with subscriptions) with per-session/daily caps and a no-progress loop killer; paid tier ($9/month) adds phone/Slack alerts and remote pause. A good fit if you use subscriptions or Claude Code. |
274
+ | LiteLLM budgets | Budgets per key, user or team in the LiteLLM proxy; budgets need its database. A good fit if you already run a LiteLLM gateway; it is a server you deploy and configure. |
275
+ | OpenRouter credit limits / provider spend caps | Account- or key-level and typically monthly (OpenRouter credit limits, OpenAI and Google spend caps). Provider caps are evaluated with a delay — Google has described about 10 minutes for the Gemini API cap — so a fast loop can overshoot. |
276
+ | AgentCap | Proxy for API-key traffic from Codex CLI, Gemini CLI or your own script: per-run cap with worst-case reservation and output clamping, kills the process group at the cap and prints why. Pro: loop breaker + Telegram/webhook alerts, $12 one-time. |
277
+
278
+ Pick what matches your setup — these tools can also be combined.
279
+
280
+ ## License
281
+
282
+ MIT — see [LICENSE](LICENSE). Copyright (c) 2026 Kutay Karahan.
283
+
284
+ The Pro license key is separate from the source license. How it is checked:
285
+
286
+ - On activation the key is validated against Polar's public license API
287
+ (`api.polar.sh`). After that it is re-checked at most about once every 7 days.
288
+ - The result is cached in `~/.config/agentcap/license.json` (overridable with
289
+ `$AGENTCAP_LICENSE_FILE`).
290
+ - If you are offline, a previously validated license keeps working for up to
291
+ 14 days since the last successful check. After that AgentCap falls back to the
292
+ free tier until the key can be validated again.
293
+ - `AGENTCAP_POLAR_ORG_ID` selects the Polar organization the key belongs to.
294
+
295
+ ## Development
296
+
297
+ ```bash
298
+ uv venv .venv
299
+ uv pip install -e '.[dev]'
300
+ .venv/bin/pytest -q
301
+ ```
302
+
303
+ Tests use mocked upstreams (`httpx.MockTransport`) and never make real network
304
+ calls; no real API keys are required.
@@ -0,0 +1,21 @@
1
+ agentcap/__init__.py,sha256=HK9PwWALuJz72O2j7KUeorZd1VLtFJ_6C2hs1w2E09Q,152
2
+ agentcap/alerts.py,sha256=u3NBCjgBLypE1GnJl7egNziR3Uq89sJVkT58zBy6FMY,10403
3
+ agentcap/clamp.py,sha256=BktNFSEZePYbT3OcVr9XCUwfgZe21DZN_jgQkKK7WEs,5984
4
+ agentcap/cli.py,sha256=KikufNiDLLkh96S3N6JWKqrKsSz2eQ_ZbqJ5H571jx4,12976
5
+ agentcap/estimate.py,sha256=W-dIaS6pD9GkH12EoFX9Vcrk3B_AX7S8Agc-_lUVQnU,9674
6
+ agentcap/ledger.py,sha256=YG9hrFdW5mGHw_kpt8xoWL-lIKshMUJMdPS2aaamIbw,13104
7
+ agentcap/license.py,sha256=QWiLAkRhhEnDCpMZNs3WKBCatD6RKCQpmDC47fhNQk0,22320
8
+ agentcap/loop.py,sha256=FxM-4JUMqwFUu9soKOnXl33YLIvVtkZIfJA44b3eunU,4164
9
+ agentcap/pricing.py,sha256=ycY4IMUqZqHCG9Alt1c5SitWEV-J4-iOV8JLemjjQ9U,21985
10
+ agentcap/proxy.py,sha256=Z8OXgq90fskBnsIMPh9h_hXpJUv9rfiMoAhgLGDyD5g,42414
11
+ agentcap/runner.py,sha256=hRCEtpd0gCx-UqlAb8WswuiXIxzc8yD5rtEjf97NTUw,16118
12
+ agentcap/upstreams.py,sha256=4voNmcWgfWJ39Z6yt2CszUObac91sEZbXt_OAgSwZWk,3906
13
+ agentcap/usage.py,sha256=9YDkdX7DnfFMqXTB0QrWL4ISsbihzCRV6yI_fEYUY6M,13462
14
+ agentcap/data/pricing.json,sha256=S5X2euk5vWHaEh6l008Aw99peCtIb3nBcPdVxJr-5Ns,12131
15
+ agentcap/devtools/__init__.py,sha256=EmCJZQ3xK6hAE3jPsu6w8f2IdwlW_akY0Stp2HH66Kg,60
16
+ agentcap/devtools/fake_upstream.py,sha256=somlmbJkwne6EZh5iMwhCrJsuouaTyLSEWoYMKAYQjc,12873
17
+ agentcap_cli-0.1.0.dist-info/METADATA,sha256=rcta3Ud_jfK1vEw-qBRTGATi1ORNNJDQ5nKBM0aytug,14007
18
+ agentcap_cli-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
19
+ agentcap_cli-0.1.0.dist-info/entry_points.txt,sha256=eUEtK13KEPXT2pO_lD6zzZWu5yHHo7EKrVQe3Fw6q4U,47
20
+ agentcap_cli-0.1.0.dist-info/licenses/LICENSE,sha256=b9WVuKHVLMITmseyT63ENNC9TbX_zg_I0oSQNJVGYJo,1070
21
+ agentcap_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ agentcap = agentcap.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kutay Karahan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.