Local LLM API proxy — captures usage, attributes cost to projects.
Project description
Halton Meter
Local LLM API proxy that captures usage and attributes cost to projects.
Halton Meter is a governance and cost-attribution tool for LLM API spend. It runs a local proxy that observes outbound traffic to LLM providers (Anthropic, OpenAI, Gemini, Groq, etc.), logs every request with project-level attribution, computes accurate cost from published pricing, and surfaces it in a dashboard.
Designed for solo developers, agencies, and in-house dev teams who use Claude Code, the Anthropic SDK, or other LLM clients heavily and want transparency over what's being spent and on what.
Quickstart
The exact happy-path sequence on a clean macOS machine:
pipx install halton-meter
halton-meter init # plug-and-play; macOS will prompt for admin password
halton-meter run claude # meter Claude Code's API calls
halton-meter report # see captured rows
That's it. halton-meter init installs the local CA cert (a macOS dialog
will pop up asking for your password), the launchd supervisor entry, and
the port allocations. By default, only commands you explicitly route via
halton-meter run <cmd> are metered — browsers, GUI apps, and Spotlight-
launched terminals are untouched, so init cannot break HSTS browsing.
Already used a previous version? halton-meter doctor prints a top-line
verdict (HEALTHY / INCONSISTENT / BROKEN) plus copy-pasteable next steps.
To extend coverage to browsers and GUI apps:
halton-meter init --gui # opt-in: also meter browsers, GUI apps
Requires Python 3.11+.
What if halton-meter init doesn't succeed?
Most failures are caught by the post-init self-test, which rolls the install back automatically and exits non-zero. Common cases:
| Symptom | Cause | Action |
|---|---|---|
| The macOS admin dialog appears, asks for your password | Expected — the cert-trust step needs admin rights | Type your account password and click OK. This is the same dialog Brew, the macOS installer, etc. use. |
--non-interactive cannot elevate ... (exit 2) |
Both osascript and pre-cached sudo are unavailable | Either run halton-meter init interactively (the GUI dialog will appear) OR pre-cache with sudo -v && halton-meter init --non-interactive. |
| Default port 8080 / 8765 is busy | Auto-fallback fires; daemon picks 8081 / 8766 | The success panel and halton-meter status show the actual port with (fallback from busy default :8080/:8765). Configure your tool to target the actual port. |
| Cert is already trusted | Idempotent path | Init skips the trust step and proceeds. Re-runnable safely. |
halton-meter status says BROKEN |
Some component drifted | Run halton-meter doctor for a row-by-row diagnosis with concrete next-actions. Each row has a copy-paste fix. |
| Live daemon already running, plist needs refresh | halton-meter init will prompt before unloading |
Confirm with y at the prompt to proceed (briefly drops the live API connection during the restart) or n to skip the supervisor refresh. |
Switching between modes (gui ↔ env-only) is a single command:
halton-meter init --gui # switch to gui (system proxy live)
halton-meter init # switch back to env-only (system proxy
# disabled, launchctl env swept, shell-rc
# block removed — full mode reconciliation
# in v0.1.4)
Full uninstall (preserves db.sqlite by default):
halton-meter uninstall # remove plists, restore proxy
halton-meter uninstall --purge # also delete config + sentinels
halton-meter uninstall --purge --include-logs # also delete db.sqlite
Two install modes
Halton Meter ships with two install modes, picked at init time. The default mode is safe (cannot break your browser); --gui opts in to broader coverage.
| Mode | Invoke | What it does | What it metres | Risk |
|---|---|---|---|---|
| env-var-only (default) | halton-meter init |
Installs the CA cert, the daemon, and the launchd plists. Does not touch the system proxy panel, the launchctl user-domain env, or your shell rc. | Whatever you explicitly route via halton-meter run <command> (Claude Code, the Anthropic SDK, python my_script.py, an interactive subshell with --shell, …). |
Cannot break HSTS browsing — we never touch the system proxy. |
| --gui | halton-meter init --gui |
All of the above, plus enables the macOS system proxy, plus writes HTTPS_PROXY / NODE_EXTRA_CA_CERTS / friends into launchd's user domain (so apps spawned via Spotlight/Dock see them), plus optionally appends an idempotent block to your shell rc (interactive prompt, opt-out via --no-shell-rc). |
Browsers, GUI apps spawned via Spotlight/Dock, terminal CLIs that respect system proxy. | May break HSTS browser sites if the cert is not trusted by SecTrust. The daemon's invariant catches this and refuses to enable the proxy when cert verification fails (P0-1 in v0.1.3). |
To switch modes after install, just re-run init with the new flag — v0.1.4 reconciles all mode-specific state automatically (no uninstall step required):
halton-meter init --gui # gui → all mode-specific state laid down
halton-meter init # back to env-only — system proxy disabled,
# launchctl env swept, shell-rc block removed
Useful commands
halton-meter init [--gui] [--no-shell-rc] # install (re-runnable; idempotent)
halton-meter run <cmd> [args...] # exec wrapper that injects metering env
halton-meter run --shell # interactive subshell with metering env
halton-meter status [--json] # mode-aware HEALTHY / INCONSISTENT / BROKEN
halton-meter doctor [--json] [--curl] # one-command diagnostic; copy into a ticket
halton-meter start | stop # supervisor control
halton-meter uninstall [--purge] [--include-logs]
halton-meter reset-proxy # emergency: disable system proxy + reset
halton-meter doctor is the diagnostic of last resort: it prints every signal that matters (daemon health, cert trust, system proxy state, launchctl env, shell rc marker, env in current process) and ends with a top-line verdict and concrete next-actions. --curl adds an end-to-end TLS smoke test against https://example.com (hard-coded — never a provider domain).
What it does
- Intercepts HTTPS traffic to LLM provider endpoints via a local mitmproxy instance
- Parses request/response bodies to extract model, tokens, cost
- Attributes each request to a project based on the calling process
- Stores everything locally in SQLite (
~/.halton-meter/db.sqlite) - Optionally syncs to a backend for dashboard visualisation
What it doesn't do
- Doesn't wrap SDKs — your code stays exactly as it is
- Doesn't intercept anything you don't ask it to — only configured LLM endpoints
- Doesn't send your data anywhere by default — runs entirely locally
- Doesn't break your workflow — if the proxy fails, traffic falls through to the real provider
Known limitations
Honest list, not a roadmap. Apps that ignore both the macOS system proxy AND HTTPS_PROXY env have no general capture path:
- Go binaries with
GODEBUG=netdns=go. Go's pure-Go resolver path bypassesHTTPS_PROXYenv in some builds. Calls reach the provider unmetered. Mitigation: launch the binary viahalton-meter run(setsHTTPS_PROXYexplicitly) — but if the binary opts out of proxy env, even that doesn't help. - libcurl callers using
--insecureor withCURLOPT_PROXYnot honoured. Same root cause: the client doesn't consult either signal.halton-meter runwill setHTTPS_PROXY, but--insecurecallers skip TLS verification entirely. - WSL2 networking on Windows hosts. v1.0 doesn't route WSL2 guest traffic through the Windows-side proxy. WSL2 + halton-meter is not yet supported. Linux-native and macOS are the supported platforms.
- Hardcoded HTTP stacks that open raw TLS sockets to known provider IPs. Anything that bypasses both system proxy AND
HTTPS_PROXYenv will reach the provider unmetered. - Claude Code (Node.js) requires
HTTPS_PROXYenv. Node honoursHTTPS_PROXY, not the macOS system proxy panel. In--guimode the launchctl user-domainsetenvcovers Spotlight/Dock-spawned apps; for terminal-launched Claude Code, usehalton-meter run claude(env-only mode) or open a new shell after the install (so the rc-appended export takes effect). - Late-coming network interfaces. macOS network services are enumerated once when the daemon starts (cached for the process lifetime). If you plug in a new interface — Thunderbolt dock, USB-tethered iPhone — restart with
halton-meter stop && halton-meter start.
Project
Halton Meter is open source under Apache 2.0. Built by Halton Labs.
- Source: https://github.com/haltonlabs/halton-meter
- Issues: https://github.com/haltonlabs/halton-meter/issues
- Security: see
SECURITY.mdin the repository
This package is the daemon component. The dashboard lives in the same repository and is run separately.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file halton_meter-0.1.4.tar.gz.
File metadata
- Download URL: halton_meter-0.1.4.tar.gz
- Upload date:
- Size: 202.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8974a9104bf37b7e27f6b631d8cc144b508a068bd95b07b6a33f40a668f703fe
|
|
| MD5 |
650b130f55fe2c3595b5c4f75da14f0b
|
|
| BLAKE2b-256 |
f987923d354df34d7fad5a00a0bbea5b9af0526e952f915231bd8f54330aba43
|
File details
Details for the file halton_meter-0.1.4-py3-none-any.whl.
File metadata
- Download URL: halton_meter-0.1.4-py3-none-any.whl
- Upload date:
- Size: 160.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22c663ff1c68cb9339706ead49b11c51999215ada907ba524112a60a39d790e5
|
|
| MD5 |
e32dfb4daa9fae1117add9b773499bf6
|
|
| BLAKE2b-256 |
a7588358ccbad3e4f33674f9d49e824bb65ca6486681c5ac70946204ec067021
|