Documentation

Use Heliast with a gateway you already run

You can keep the gateway you have. Heliast does not replace it. The gateway keeps routing, retries, caching and your own rate limits. Heliast's enforcement hook decides whether each request may reach a model, and writes the ledger row before the answer.

How it fits

A small adapter runs inside your gateway. For every model call it does two things:

  1. Before the call, it asks the hook whether the request is allowed. The hook checks who is asking, whether the model is admitted at the version your policy names, and whether your policy entitles the caller. It writes the decision to the ledger and only then answers. The adapter obeys the answer.
  2. After the call, it sends the hook the token counts and a hash of the answer. The hook writes the inference row. It never sees the answer text.

If the hook cannot be reached, cannot write the ledger, or answers with anything other than allow, the adapter refuses the request. Nothing reaches a model unrecorded.

Admission and Compare do not depend on your gateway. The catalogue and verdicts are the same wherever a model runs, and Compare needs only an OpenAI-compatible endpoint.

What the ledger shows

The ledger row names the caller your gateway authenticated, in a namespace of its own. The subject reads gw-litellm:alice and the key id reads gw-litellm:team-key-1, so a gateway user can never share usage, rate limits or a budget with a Heliast user or with another gateway's user who happens to have the same name. A model is shown with its own class, so models that run in different places appear in one list: admitted models, your own assessed and registered models, and hosted routes. A hosted route is never labelled verified.

What you need to do

  • Run the Heliast hook inside your environment, as described in deploying.
  • Give the hook an adapter token. The token lets the adapter speak for the caller your gateway authenticated, so treat it like the admin token: a secret, one per adapter, never in a repository. Set it on the hook as GATEWAY_ADAPTER_TOKENS, in the form name=token,name=token. Without it the hook does not trust any adapter. The hook refuses to start if a token is shorter than 32 bytes, if two adapters share a token, if a token equals the hook or admin token, or if a name is not lower case letters, digits, - or _.
  • Decide which roles each adapter may assert. By default an adapter may assert only standard. To allow more, set GATEWAY_ADAPTER_ROLES on the hook, for example litellm=standard|premium. The role is set in the adapter's configuration, never by a gateway user.
  • Install the adapter for your gateway. There are pages for LiteLLM and Bifrost.
  • Make the models reachable only from your gateway. The adapter decides every request that goes through the gateway. A path to a model that skips the gateway is not seen.

Limits you should know

  • Only what goes through the gateway is decided. Closing the direct routes to your models is yours to do, with network policy. Some gateway routes reach a model without running the adapter at all. Each adapter page lists the ones measured and how to close them.
  • Names the hook will store. The subject, groups and key id must be printable text. A group is one word: a team called finance ops is refused rather than split into finance and ops, so name teams without spaces. An adapter may assert at most 32 groups.
  • Transport. The adapter token travels in a header, so the hook address must be https. The adapters refuse a plain http address unless it is on the same machine or you set HELIAST_ALLOW_INSECURE_HOOK=1 after deciding the network is protected.
  • A fallback can answer with another model. If your gateway falls back from one model to another, the model that answers may not be the one the hook decided on. Some adapters ask the hook again for each attempt, so a fallback is decided on its own model. Where the gateway does not, the hook records the mismatch on the ledger as an anomaly: for a response that is not streamed the adapter withholds the answer, and for a streamed response the answer has already been sent and is only recorded. Each adapter page says which applies. Where it is the second, configure fallbacks only between admitted models your policy entitles.
  • Model names. Your gateway may rename models. The hook resolves the name the client sent. An admitted id resolves; a name your gateway invented does not, unless a host record maps it to an admitted id. An unknown name is refused with a reason.
  • Your own limits stay yours. Your gateway's rate limits and budgets are not replaced. The reference Heliast policy decides entitlement only; it passes your policy the ledger's usage figures, so your own rules can add limits if you want them.

If you are writing an adapter

The hook has two calls. Both need the header X-Hook-Token carrying the adapter's token.

CallSendAnswer
POST /authz/<original path>The client's request body, unchanged, and the asserted caller: X-Heliast-Adapter-Subject (required), X-Heliast-Adapter-Groups, X-Heliast-Adapter-Role, X-Heliast-Adapter-Key-Id200 to allow, with the request id, policy revision, subject, key id and decided model in response headers (the adapter package lists their names). 401 or 403 to refuse, with the reason in the body. 503 if the ledger could not be written.
POST /hook/responserequest_id, subject_id, virtual_key_id, policy_revision as the hook returned them, plus model, prompt_tokens, completion_tokens, latency_ms, completion_hash200 with recorded: true. If the model that answered is not the model decided on, the body also carries anomaly with the reason.

An adapter must refuse the request on anything but 200 from the first call, and on a call type it has no path for. It must not send prompt or completion text anywhere except the first call's body.