Minibridge is a proof-and-metering service for LLM API calls.
It sits between a caller and an upstream LLM provider, keeps the API key inside a trusted boundary, executes the call, returns the response to the caller, and emits a tamper-evident receipt that proves the request, the response, and the billable usage.
The cost bearer is the provider / key owner, not the caller. The caller submits work; Minibridge proves what was spent.
The service boundary is narrow:
- it receives a request for an LLM call,
- keeps the API key inside a trusted boundary,
- forwards the call to the model provider,
- records the exact request/response metadata and token usage,
- computes a cost from a pinned pricing table,
- signs a tamper-evident receipt.
The current code is TEE-ready, but it is not tied to a specific hardware enclave yet. The design is meant to be moved behind a TEE or HSM later.
The service is split into two layers:
- the untrusted outer service: HTTP, orchestration, storage, admin flow
- the trusted inner boundary: API key handling, LLM provider calls, receipt signing, attestation evidence
The HTTP surface supports both generic and provider-specific calls:
POST /callPOST /provePOST /providers/{provider_id}/callPOST /providers/{provider_id}/proveGET /providersGET /proofsGET /proofs/{proof_id}POST /register-provider
For a full usage walkthrough, see docs/usage.md.
- the request hash
- the response hash
- the model name and parameters
- token usage returned by the provider
- the computed cost under a pinned pricing table
- that the receipt was signed by the service
- one-time request IDs, expiry times, and caller allowlists
- a typed key policy rather than ad hoc enrollment fields
- that the provider independently signed the same bill
- that the agent was correct outside the service boundary
- that the host machine was trustworthy unless the service runs inside a real TEE
src/minibridge/core/— shared domain objects: requests, receipts, proofs, pricing, signing, attestation, verificationsrc/minibridge/providers/— provider registry and OpenAI-compatible provider adapterssrc/minibridge/proof/— the proof service and call/prove orchestrationsrc/minibridge/transport/— HTTP server and request handlerssrc/minibridge/app/— CLI and local state persistencesrc/llm_api_proof/— compatibility package that re-exports the Minibridge modulesexamples/mock_run.py— end-to-end demo using the mock providerexamples/http_demo.py— end-to-end demo using the HTTP servicedocs/provider-registration.md— provider registration payloads for OpenAI, OpenRouter, Chutes, and mockconfigs/minibridge.demo.json— demo bootstrap config for local or container useDockerfileanddocker-compose.yml— containerized demo runtimeweb/— separate frontend app boundary for the Minibridge dashboard
python3 examples/mock_run.pyThe demo prints a signed receipt and verifies it locally.
To run the HTTP service demo:
python3 examples/http_demo.pyInstall the project in editable mode and use the minibridge command:
pip install -e .
minibridge --helpRun a local service with a generated signing key:
minibridge serveThat writes a private signing key file and a matching public key file, then starts the HTTP service.
By default it also writes .minibridge-state.json, which persists providers, keys, and receipts across restarts. Use --state-file "" to disable persistence.
Register a provider and a key against a running service:
minibridge providers add --payload - --server http://127.0.0.1:8080
minibridge keys add --payload - --server http://127.0.0.1:8080The provider payload examples are in docs/provider-registration.md.
Submit a request through the service:
minibridge call --payload docs/request.json --server http://127.0.0.1:8080Capture a public proof bundle:
minibridge prove --payload docs/request.json --server http://127.0.0.1:8080Create a SparkProof-style offline bundle from a running service:
minibridge bundle create --server http://127.0.0.1:8080 --bundle bundles/run-001Verify that bundle on any CPU host:
minibridge bundle verify --bundle bundles/run-001The HTTP API also exposes:
GET /bundleGET /bundle/exportGET /bundle/manifest
Verify a receipt offline:
minibridge verify --receipt docs/receipt.json --public-key-file .minibridge-signing.key.pubYou can also verify a proof bundle directly:
minibridge verify --proof docs/proof.json --public-key-file .minibridge-signing.key.pubFor unattended startup, use minibridge serve --config <file>.json with a bootstrap file that includes pricing_table, optional providers, and optional keys.
To run the host control plane on this machine:
minibridge host serve --host 0.0.0.0 --port 7070To run a CPU-TEE runner inside Phala or another dstack CVM:
minibridge serve --host 0.0.0.0 --port 8000 --config configs/minibridge.runner.phala.json --state-file ""The runner config supports api_key_env for secrets injected by the TEE runtime. The included Phala template expects OPENROUTER_API_KEY in the environment.
If you use the included Phala compose file, the container listens on 8000 but the public URL uses host port 18081, for example:
curl https://<app-id>-18081.dstack-pha-prod9.phala.network/healthFor a containerized demo, run:
docker compose up --buildThat starts the host control plane on http://127.0.0.1:18080 and the web UI on http://127.0.0.1:5173.
For a Phala-style runner container, use:
docker compose -f docker-compose.runner.yml up --buildThe web UI lives under web/ and talks only to the HTTP API. It can be run independently of the Python package.
With the included compose stack, the API is published on http://127.0.0.1:18080 and the UI on http://127.0.0.1:5173.
See docs/provider-registration.md for copy-pastable POST /register-provider payloads and a provider-specific call example.
See docs/usage.md for the end-to-end usage guide, including bundles and verification.