Skip to main content

focxle

See what every AI agent costs you, across every vendor. In one line, with no account, in under a second.

Nothing you already have can tell you what one agent cost. Your OpenAI dashboard cannot see Anthropic. Neither can see Serper, Firecrawl, or the twelve other APIs your agent calls in a loop at 3am. They all report per key and per month, which is the wrong unit twice over: you do not run a key, you run agents, and by the time the month closes the money is gone.

focxle runs inside your process, so it sees every one of them, attributes them to the agent that made the call, and prices them from the vendor's own token counts rather than a guess. Connect an account and payments your agent settles on-chain land in the same total.

Why the number gets large fast. Do the arithmetic on a stuck agent. Two frontier-model calls a second, 10k tokens in and 1k out, at $5 per million in and $25 per million out, is 7.5 cents a call and $540 an hour. Twelve hours overnight is $6,480. A two-day weekend is $25,900. Nobody budgets for this, because nobody plans it: it is a bad stopping condition, one retry wrapper too many, a tool that feeds its own output back into the prompt. The first anyone hears is the invoice.

That is the entire reason this exists. It is free, forever, to watch it happen and to see exactly what a cap would have stopped before you pay for one.

This library fails open. It runs inside your agent, so the worst thing it could do is break a request it was only supposed to measure. If anything inside it fails, your call goes through and the failure is counted and printed at the end. focxle.init(fail_open=False) inverts that if an unmeasured call is genuinely worse for you than a failed one.

It blocks nothing by default. Out of the box it only measures. Refusing a call needs an account on a paid plan, and even then the instruction comes from a signed document rather than a local setting, so nothing you or we write in code can quietly switch it on. Calls to vendors we cannot price are always allowed through.

pip install focxle
import focxle
focxle.init()

That is the whole setup. No account, no API key, no config file, and no network call. Prices ship with the package, so the first run works on a plane. Telemetry is off unless you turn it on, and we ask exactly once.

What you get

  focxle spend                                          $47.21
  --------------------------------------------------------
  support-triage                          $31.04  (1,284 calls)
      anthropic                                         $28.10
      google.serper.dev                                  $2.94
  research                                $16.17  (203 calls)
      openai                                            $14.02
      api.firecrawl.dev                                  $2.15

  3 calls would have been stopped under $1.50/call and $50/day
  $12.30 prevented, worst single call $4.10
      3x  single call $4.10 over the $1.50 per-call limit
  $5,904 a month at the rate this run was going
  $412.60 prevented across 17 runs in 9 days
  observe mode: nothing was actually blocked

  prices dated 2026-08-05

  turn these into real caps: https://focxle.com/upgrade

The second block is the point. It is what a cap would have done, evaluated by the same code that would do the blocking, printed so you can decide whether you want one before you pay for one.

Every figure there is a measurement, not a sales number. The total, the worst call and the running total are sums of calls that really happened, priced from the vendor's own usage numbers. The monthly figure is the only projection, it is this run's own measured rate carried forward, it says so on the line itself, and it is withheld entirely unless the run was long enough and busy enough to mean anything.

If a cap would have stopped a large share of your calls, it says that instead of quoting a figure. A cap that blocks a quarter of an agent's work is not saving money, it is stopping the agent, and calling the difference a saving would make the number worthless on the day it matters. Nothing is offered for sale on those runs either.

Why there is nothing else quite like this

Cost tools for AI fall into three shapes, and all three ask you for something before they tell you anything.

Vendor dashboards are per key and per month, one per vendor, and none of them can see the others. Four vendors means four tabs and no total.

Proxies and gateways see everything, because every call now goes through somebody else's server. That is a new dependency on your live path, a new company holding your prompts, and a new thing that can be down at 3am.

Observability platforms want a trace pipeline, an account, and a seat or per-trace bill before the first number appears. Several are excellent. All of them are a project, and none of them is something you do at 4pm because you got a surprising invoice at lunchtime.

focxle is pip install focxle and one line. It has zero dependencies, so nothing enters your environment and nothing can conflict with your pins. It makes zero network calls on the free path, which the test suite proves by deleting socket.socket and running the whole suite anyway. It needs no account, no key and no config file, and the price table ships inside the package, so the first run works on a plane. It fails open by construction: the worst thing a bug in here can do is fail to measure a call that still went through.

And it answers the question none of the others can: what did this agent cost me, across everything it touched.

Attributing spend to an agent

Per agent is the number nobody else can show you, and it only exists if calls are labelled.

with focxle.agent("support-triage"):
    result = my_agent.run(ticket)

Works across threads and async tasks. Or set FOCXLE_AGENT in the environment, which is usually right, because the same image is normally deployed as several different agents.

Exact token counts

The HTTP layer already sees your model calls. Wrapping the client upgrades them from "a request happened" to the vendor's own token counts.

from openai import OpenAI
client = focxle.watch(OpenAI())

Streaming is handled. Wrapping the same client twice is a no-op rather than a double count.

For LangChain, where the framework builds the client for you:

chain.invoke(x, config={"callbacks": [focxle.langchain_handler()]})

Reading the numbers yourself

focxle.spend()                      # total USD observed
focxle.spend("support-triage")      # for one agent
focxle.counterfactual()             # what a cap would have stopped
focxle.report()                     # print now instead of at exit
focxle.init(file="~/spend.jsonl")   # one JSON object per call

What it does not do

It does not block anything on its own. With no account, policy evaluation runs and the verdict is only recorded, so you see what a cap would have done before you decide you want one. Policy(mode="enforce") written in your own code is refused and downgraded to observe, with a note on stderr: enforcement is something an account is granted, not a flag a process sets for itself.

When it is granted, caps are judged on what you have actually spent, not on a guess at what a call is about to cost. Output length cannot be known before the reply is written, so guessing it refuses ordinary work and misses the runaways. The one exception is the per-call ceiling, which has to be decided in advance: it prices the max_tokens you asked for, so set it above what your largest declared reply would cost rather than above what calls typically cost.

It does not price everything. A vendor missing from the price table is recorded at zero, and both the host and the exact model id are named in the report, so a zero that means "free" is never confused with a zero that means "we did not recognise this". The call is allowed through. Blocking a call because we do not know what it costs would be this library making a decision on missing information inside a process that trusted it to be passive. An invented figure would be worse, because it looks like knowledge.

Routers are priced as the provider they name, so a call through OpenRouter to anthropic/claude-haiku-4.5 costs what that model costs. Dots and dashes in a version are treated as one spelling, because which one you see depends on whose SDK produced the string.

It is per process. An agent running across fifty workers produces fifty partial pictures. Reconciling them needs somewhere to send them, which is what an account is for. The one exception is the running total of what a cap would have prevented, which is kept in ~/.focxle/lifetime.json so a second run does not start from zero. It holds two numbers and a date, never leaves your machine, and FOCXLE_NO_LIFETIME=1 stops it being written at all.

Everything under ~/.focxle is created for your user only, 0700 on the directory and 0600 on the files, the way ~/.ssh and ~/.aws/credentials are. Your account id is a credential: whoever reads it can read that account's spend and start a checkout against it, and agent workloads run on shared CI runners constantly. Anything an earlier version left world readable is tightened the next time it is written.

It has no dependencies. Nothing is added to your environment and nothing can conflict with your versions. The SDKs and frameworks it instruments are detected at runtime and never imported at install time.

What is sent anywhere

Nothing, unless you turn it on. There is no network call on the observe path at all, which the test suite asserts by removing socket.socket and running anyway.

There is exactly one thing we ask for, printed once after your first breakdown and never again. It is off until you type a command:

python -m focxle share preview   # the exact JSON, before you decide
python -m focxle share on
python -m focxle share off

If you turn it on, it sends anonymous vendor totals: which vendors you used, how many calls, how much, and the hosts we could not price. That last one is the whole reason we ask, because it is how we know what to price next.

It never sends your agent names, your model names, prompts, responses, URLs or anything derived from your machine. The install id is a random UUID generated locally, not a hash of your hostname, because anything derived can be reversed by whoever holds the same input. Private hosts (.internal, .corp, bare names, IP addresses) are dropped from every field and counted under withheld, so the totals are visibly partial rather than quietly so.

It never prompts. This runs at process exit, often with no terminal attached, and blocking on stdin there would hang a production agent.

If you enable the local file sink, it records the host and the first two segments of the path, never query strings, so your search terms and document ids stay out of it. That file never leaves your machine.

Compatibility

Python 3.9 and up. Instruments openai, anthropic, httpx, requests and LangChain when they are present, and does nothing when they are not.

Licence

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

focxle-0.1.3.tar.gz (49.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

focxle-0.1.3-py3-none-any.whl (59.7 kB view details)

Uploaded Python 3

File details

Details for the file focxle-0.1.3.tar.gz.

File metadata

  • Download URL: focxle-0.1.3.tar.gz
  • Upload date:
  • Size: 49.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for focxle-0.1.3.tar.gz
Algorithm Hash digest
SHA256 a6132b584bd1e7f40889a0fde42f2d52312fbd15d6c9466c0744690311f22eb6
MD5 846dcce97c4137ccfa8233a7357676cd
BLAKE2b-256 1692461aab687f860ba0886b44c96e1c12637211155e9779c67959c0f870833a

See more details on using hashes here.

File details

Details for the file focxle-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: focxle-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 59.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for focxle-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e72a5cf174d78e4bad43af25c7e3710cd41db60133dd4408da33e4bfaefab272
MD5 bb5ff8b89d0bf7d7f30283ad335f28c6
BLAKE2b-256 e69ba87fba0f15a62a8b229f84cff91008b6c5ead0961d45dcba4ce18138559b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page