floe-guard: a spend meter and budget gate for AI voice agents
The spend meter, cost/margin, & budget gate for AI voice agents. Meters STT + TTS + LLM + telephony per call, out of the box (Pipecat, LiveKit — Python & TypeScript). Hard-stops the next turn before it crosses your ceiling. Local, no account, no telemetry. Built by Floe.
At a glance
- What is it?
- floe-guard prices the STT, TTS, LLM and telephony legs of a voice call from a bundled cost map and raises BudgetExceeded before the next turn crosses your ceiling. It is local, MIT licensed, and honest about being estimate-based.
- Who is it for?
- Adopt floe-guard if you run Pipecat, LiveKit, Vapi or Retell voice agents and want a per-call cost figure and a ceiling that stops runaway loops without sending data anywhere. Skip it if you need serverless-safe cross-process budgets or exact post-hoc billing, because the project itself flags estimate-based enforcement, cold-start concurrency and shared-SQLite locking as open limits.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The bill a token-level cost tracker misses
A voice agent spends across several vendors on a single call: the carrier, the speech-to-text provider, the model, the voice synthesis service, and any paid tools the agent invokes. A tracker that only counts prompt and completion tokens reports the LLM leg and stays silent about the rest. The README states this directly: that is the answer a token-level tool cannot give, because it meters the LLM leg and misses the rest of the bill.
floe-guard is aimed at developers building voice agents on Pipecat, LiveKit, Vapi or Retell in Python or TypeScript, and at the people who have to answer what a call cost and whether a loop can drain an account overnight. The README's framing of the failure mode is concrete: a hard-stop at $0.10 instead of $4,000. The project is local by default, needs no account, and the README says there is no telemetry by default. Connecting to hosted Floe is a separate, opt-in step.
How the guard prices a call and blocks the next turn
The mechanism has two parts. Pricing comes from a bundled cost map, described in the estimate output as a snapshot of public US list prices, so per-leg rates do not have to be entered by hand. Enforcement is contract-based: the README says adapters gate LLM calls automatically, and for paid tools reserve_tool() and settle_tool() block before the call runs. The distinction matters. record_tool() alone meters after the fact, so it cannot stop a call already made.
The basic Python flow is a check before the call and a record after it. BudgetGuard holds the ceiling, check() raises if the next call would cross it, and record() writes the tokens that were actually spent. The guard prints a block message showing spend so far against the ceiling when it fires. For voice, the per-leg example in the README prices each component separately: livekit-stt at $0.001027 for 8s of Deepgram Nova-3, gpt-4o at $0.003700 for 600 in and 220 out tokens, livekit-tts at $0.009000 for 180 characters of ElevenLabs Flash, and livekit-telephony at $0.012750 for 1.5 minutes of Twilio US inbound, for a total of $0.026477. That decomposition is the product: you see which leg dominates, not just a single number.
The README also documents pre-call admission gates for voice, which is where a ceiling stops a call before it starts rather than mid-turn.
Install, run the offline demo, then price a workload
Python installs from PyPI and TypeScript from npm. The README gives both commands.
pip install floe-guard # Python
npm i floe-guard # TypeScript (Vercel AI SDK) — see js/The fastest way to see the guard fire is the bundled demo. The README says it rigs a loop against a stub LLM, so it needs no API key, no account and no network. It prices each fake gpt-4o call offline and halts the loop after a few iterations, before the $0.10 ceiling is crossed.
pip install floe-guard
floe-guard demoBefore committing to a ceiling, price the workload you expect. The estimate command takes a model name and call shape and prints a per-call and total figure from the same cost map the guard enforces against.
floe-guard estimate gpt-4o --calls 1000 --tokens-in 800 --tokens-out 300The README shows the output as $0.005000 per call and $5.000000 total, with the price source labelled as cost_map and an offline snapshot. It then prints a BudgetGuard line with limit_usd set to the run total, so the ceiling you set is the cost you just saw. Models that cannot be priced fail closed with an error rather than a $0.00 guess, which is the right default for a gate.
The wired-up version in application code looks like this, with your own LLM call in the middle.
from floe_guard import BudgetGuard
guard = BudgetGuard(limit_usd=5.00) # your ceiling
guard.check() # before each LLM call — raises if it'd cross
response = call_your_llm(...) # your existing call
guard.record("gpt-4o", response.usage.prompt_tokens, response.usage.completion_tokens)The voice example needs the extra and a repository checkout, because the README notes examples are not shipped in the wheel.
pip install "floe-guard[livekit]" # the demo imports livekit-agents
python examples/voice_call_cost_livekit.py # needs a repo checkout — examples/ aren't in the wheelThe limits the project puts in its own metadata
The pyproject.toml is unusually candid. It keeps the classifier at Development Status :: 4 - Beta and explains why: estimate-based enforcement, cold-start concurrency not bounding the first parallel wave, cross-process persistence needing a shared SQLite file with reliable locking (described as not serverless-safe), and approximate stream cut-offs. The comment says Production/Stable would overclaim maturity until those are closed or clearly acceptable. Treat that list as the adoption checklist rather than as marketing hedging.
The practical consequences are worth spelling out. If your agent fans out several parallel calls at cold start, the first wave is not bounded by the ceiling. If you run multiple processes or workers, the budget only holds across them when they share a SQLite file with working locks, which rules out typical serverless deployments. Streaming responses are cut off approximately, not at an exact token boundary.
There is also a scope limit in the metering model itself. record_tool() meters a paid tool call after it happens, so it cannot prevent that call. Only reserve_tool() and settle_tool() block before execution. If your guard is built entirely on record-style calls, you have an accounting ledger, not a gate.
Finally, the hosted tier is a different product surface. The README describes hosted Floe as the system of record on top, with server-side spend controls, client and campaign attribution, and a $2K/month tracked limit on the free connection. Local use has no such cap because there is no service involved.
Where a plain token counter or a provider dashboard fits better
If your agent is text-only and calls a single model vendor, a token counter built on the provider's usage object covers the same ground with less wiring, and the provider's own dashboard gives you the invoice-level truth after the fact. floe-guard's advantage appears when a call spans multiple vendors, which is the normal shape of voice. The README's own comparison is between a per-leg voice total and a token-level tool that reports only the LLM portion.
The other real alternative is doing nothing in-process and relying on provider-side spend limits or alerts. That approach is exact, since the vendor knows what it billed, but it acts after the spend and it is per-vendor, so no single number tells you what one call cost across carrier, STT, TTS and model. The trade is timing and aggregation against precision: floe-guard estimates from a price snapshot and stops the next turn, while a vendor cap is authoritative but late and fragmented.
Maintenance, upgrades and the MIT licence
The repository is not archived and the last push was on 2026-09-15. The pyproject.toml pins hatchling below 1.32 with a detailed comment: 1.32.0 emits Metadata-Version 2.5, which the pinned pypa/gh-action-pypi-publish@v1.14.0 rejects, and 1.31.0 is the last release emitting 2.4 that both twine and PyPI accept. That pin is a build-time concern for anyone publishing a fork, not for users installing the wheel, but it tells you the release pipeline is deliberately conservative.
The cost map is a snapshot of public US list prices. Vendor pricing changes, so the accuracy of every estimate and every enforcement decision depends on how current that bundled map is in the version you install. Upgrading is therefore not only a code change; it is a repricing of your ceilings. Check the map after a version bump before trusting a limit you tuned earlier.
The licence is MIT, declared in pyproject.toml and in the LICENSE file at the repository root. That permits commercial use and modification. It also means the authors give no warranty, and nothing here is legal advice; if you redistribute the bundled price data, confirm the terms of the underlying sources yourself.
Editorial conclusion
Adopt floe-guard if you run Pipecat, LiveKit, Vapi or Retell voice agents and want a per-call cost figure and a ceiling that stops runaway loops without sending data anywhere. Skip it if you need serverless-safe cross-process budgets or exact post-hoc billing, because the project itself flags estimate-based enforcement, cold-start concurrency and shared-SQLite locking as open limits. Verify first that your STT, TTS, LLM and telephony vendors appear in the bundled cost map, then run floe-guard estimate for your expected call shape before you set limit_usd.
Frequently asked questions
Does floe-guard send my prompts or call content anywhere?
The README states the guard runs in-process with no account and no telemetry by default. Pushing the ledger to hosted Floe is an explicit step: you save it with guard.export_log() to a JSONL file and run floe-guard push <file>, which the README describes as opt-in and limited to priced spend events, with no prompts or content leaving your process.
Can floe-guard stop a paid tool call before it runs?
Yes, but only through the reserve and settle pair. The README says reserve_tool() and settle_tool() block before the call runs, while record_tool() alone meters after the fact and cannot stop a call already made.
What happens when a model has no price in the cost map?
The README states that unpriceable models fail closed with a clean error rather than a $0.00 guess, so a missing rate cannot silently disable your ceiling.
Community notes