CollieAi guardrail for LiteLLM
A LiteLLM proxy guardrail that checks each eligible chat call against your CollieAi policy, before and after the model call. It runs in Monitor mode: it never changes or blocks a call, and never delays one beyond its own deadline. What CollieAi found goes into LiteLLM's guardrail log and CollieAi's audit. This release is a beta and only observes.
You need a CollieAi project and its API key (clai_…). This beta runs
only the project's dictionary rules: read
Your project's policy before you start.
- Tested with: LiteLLM proxy 1.102.4, Python ≥ 3.11. Use 1.102.2 or later: 1.102.0 and 1.102.1 carry the critical advisory GHSA-7hp6-4w63-5g45. Other LiteLLM versions are untested.
- Depends on:
httpx, which LiteLLM already has. Nothing else.
Install
Into the LiteLLM proxy's Python environment (or its image):
pip install collieai-litellm-guardrail
Configure
In the proxy's config.yaml:
guardrails:
- guardrail_name: collieai-monitor
litellm_params:
guardrail: collieai_guardrail.guardrail.CollieAIGuardrail
mode: [pre_call, post_call]
default_on: true
api_base: https://app.collieai.io/v1/integrations/litellm
api_key: os.environ/COLLIEAI_API_KEY
| Setting | Default | Meaning |
|---|---|---|
api_base |
— | CollieAi's LiteLLM integration base URL. The adapter posts to <api_base>/beta/litellm_basic_guardrail_api |
api_key |
— | Your CollieAi project key, clai_… |
deadline_ms |
2500 | Each phase's whole deadline: connection, send, reply and parse |
network_margin_ms |
500 | The part of the deadline kept for the network. CollieAi gets the rest as its budget |
max_body_bytes |
458752 (448 KiB) | A larger request is not sent and counts as bypass limit. The default matches CollieAi's narrow profile |
forward_conversation_id |
false |
Forward the caller's x-collieai-conversation-id header, and only that header |
summary_interval_s |
60 | How often each worker logs its counts |
synthetic_interval_s |
300 | How often each worker runs the synthetic check; it also runs at start. 0 turns it off |
Keep mode: [pre_call, post_call] and default_on: true. Otherwise one
phase, or the calls that don't name the guardrail, are not observed. The
adapter warns about both at start.
A setting the adapter can't run with stops the proxy at start. The error names the setting, never its value. Such settings:
- an unset
COLLIEAI_API_KEY; - a key that isn't
clai_…; - an
api_basethat isn't an http(s) URL with a host; - an
api_baseonhttp://anywhere but this machine (127.0.0.1,::1,localhost): the key and the caller's text would cross the network unencrypted; - a
modewith anything butpre_callandpost_call, also underLITELLM_STRICT_GUARDRAIL_MODES=false; - a number out of range.
LiteLLM's own handling of a guardrail's bad setting is different: it logs
one ERROR, Skipping guardrail …, and starts the proxy without the
guardrail. The adapter's error is not of the kind LiteLLM skips, so the
start stops instead of running unobserved. Two cases stay LiteLLM's:
- an entry without
modeis skipped that way before the adapter is built; - a misspelled setting is passed on like any other key, so the adapter doesn't see it and uses the default.
Your project's policy
This beta runs two of CollieAi's rule types: dictionary matching
(aho_corasick) and normalization. Each phase runs the policy's rules for
its direction: Input rules for pre-call, Output rules for post-call. If one
of them is outside what the beta runs, the phase is refused as a whole. The
call goes on unchanged, and the phase is a bypass capability. That
happens with:
- a rule of any other type: regex, structured IDs, URL rules, LLM detection and so on;
- more than 16 rules for one direction, or more than 8 dictionary rules;
- a dictionary rule on a dictionary group, a dictionary over 256 KiB, or a
match mode other than
substringwithwhole_wordon; - a
normalizationrule withtrim_punctuation.
CollieAi's Logs show such a check with the error capability:<what>, for
example capability:rule_type. The synthetic check at start meets the
same refusal and logs bypass:capability.
Set the policy up before you connect the proxy. A new CollieAi project
starts with the Starter Monitor policy, which has rules of other types, so
a new project alone still gives bypass:capability:
- Give the guardrail's project a policy that holds only
aho_corasickrules andnormalizationrules withouttrim_punctuation, within the limits above. Create one, or delete or disable every other Input and Output rule in a policy no other project uses. - Send a test request through the proxy. The next summary must show
completedfor both phases.bypass:capabilitymeans a rule is still outside what the beta runs.
What it checks
It checks foreground, non-streaming Chat Completions text with one choice. Every other call passes through unchanged, is not sent, and is counted as outside the supported profile under one reason:
| Reason | The call |
|---|---|
call_type |
Is not a Chat Completion (Responses, embeddings, …), or its type is unknown |
streaming |
Streams |
multiple_choices |
Has n > 1, or a response has several choices |
tool_definitions, tool_calls, tool_message |
Carries tools |
non_text_input, non_text_output |
Carries images, audio or other non-text parts |
reasoning |
Has the model's reasoning in the request or the response (reasoning_content, thinking_blocks, reasoning_items, reasoning), which the adapter does not send |
content_missing |
Has no content: null, no parts, no choice. An empty string is content and is checked |
malformed |
Is not shaped like a chat call |
Each phase of an eligible call makes one POST to CollieAi:
- no retries and no redirects;
- the reply is read within
deadline_ms; - the call itself goes on unchanged whatever happens.
The phase ends one of two ways:
- completed: CollieAi checked every item;
- bypass: no check. The reason is CollieAi's typed error (
auth,not_found,capability,limit,shape,busy,deadline, …) or the adapter's own:timeout,transport,protocol,adapter_error, orcancelledwhen the caller's call was cancelled.
A bypass is never counted as a check.
Added latency. Pre-call runs before the model call and post-call after it, each with its own deadline. A call waits at most two deadlines: 5 s with the defaults.
LiteLLM's guardrail log
Each phase adds a StandardLoggingGuardrailInformation record with
guardrail_provider: collieai.
guardrail_status:
| Status | When |
|---|---|
success |
The check found nothing |
guardrail_flagged |
The check found something Enforce would mask or block. The call still went through unchanged |
guardrail_failed_to_respond |
Bypass: no check |
not_run |
Outside the supported profile |
guardrail_response carries:
resultandeffective, which is alwaysallow;- for a completed check:
would(CollieAi'swould.outcome),degraded, and CollieAi's diagnostics: evaluation ID, coverage, rule IDs and types, timings; - for a bypass or a call outside the supported profile:
reason,detailandhttp_status; operation_id, the same for both phases of a call. Pre-call puts it in the request's metadata ascollieai_operation_id, with a tag only this worker process can make,collieai_operation_tag. Post-call and the summary's count take it back only with that tag, so an ID the caller writes there is never used.
It never carries text. LiteLLM's credential masker hides
policy_fingerprint. Use evaluation_id or operation_id to find the
check in CollieAi's audit.
LiteLLM's own request and response logging is separate from this adapter: review what it keeps on its own.
Logs
The adapter logs under the logger collieai_guardrail. It logs counts,
phases, reason codes and HTTP statuses. It never logs a text, the key or a
call's identifiers.
| Line | Level |
|---|---|
… observation bypassed (<reason>, detail=…, http_status=…) |
WARNING for a call, at most once a minute per phase and reason, with the number held back. Not for the synthetic check, which has its own line |
collieai guardrail summary {json} |
INFO, every summary_interval_s |
… LiteLLM logged N eligible calls and the hook has never run … |
WARNING: the guardrail is not wired for that phase |
collieai guardrail synthetic check: … |
INFO when both phases completed, or when CollieAi answered busy and the check will be repeated; WARNING with each phase's reason otherwise |
… LiteLLM no longer has this instance among its callbacks … |
INFO: the guardrail was deleted or rebuilt; see Turning it off |
httpx logs each request's URL at INFO under its own logger. It carries no
key or content.
A stock proxy gives handlers only to LiteLLM's own loggers, and the INFO lines above would show nowhere. So the adapter sets up its logger itself:
- if you haven't set a level for
collieai_guardrail, it logs from INFO; - if no handler up its chain takes INFO, it adds its own, on stderr, for the levels those handlers drop. Each line still goes out once.
With json_logs: true under litellm_settings, its lines go to LiteLLM's
JSON handler. With only the JSON_LOGS variable, they stay plain text
among the JSON lines.
The summary
The summary holds one object per phase. Its counts cover the interval, per worker process:
hook_calls: the hook ran;eligible: the call is in the supported profile;attempted: a POST started;completed: checks;bypass: no check, by reason;outside: outside the supported profile, by reason;logged_calls,logged_eligible,logged_outside: what LiteLLM's success and failure log events counted, apart from the hooks, one per call. The router logs every attempt of a call it retries, each with the request's metadata and theoperation_idpre-call put there; the further attempts count aslogged_repeats.litellm_call_idcan't tell calls apart: LiteLLM takes it from the caller'sx-litellm-call-idheader, and a client may send one for a whole session. A call pre-call never saw has nooperation_id, so each of its attempts counts as a call: a hook that does not run still shows.logged_outsidehas the reasons above and two of its own:rejected: the proxy itself refused the call: a bad key, a limit, a budget, or another guardrail's block, before the model or after it;malformedalso counts LiteLLM's background health checks of a model, which carry no messages.
Derived values:
-
coverage: of the checks that ended in the interval, the share that completed:completed / (completed + bypass). A check can start in one interval and end in the next, so it is not taken ofeligible, which counts starts.nullwhen no check ended; -
outside_share: calls outside the supported profile out of all the hook saw. Read it next tocoverage, so excluded traffic doesn't hide behind a good one; -
logged_unseen: eligible calls LiteLLM logged, less those a hook saw in the same interval. It is approximate:- a call that crosses the interval's end moves it by one;
- a call the hook saw and another guardrail then blocked takes one off.
A value that keeps growing means some calls skip the hook.
The not-wired WARNING needs two things: the phase's hook has never run in this worker, and LiteLLM logged eligible calls in the interval. A hook that ran in one minute for a call LiteLLM logs in the next does not trigger it.
synthetic holds the last synthetic check's result per phase.
Checking it works
- Within 3 s of start, the synthetic check posts a fixed text through
the same client, key and deadline. It is not counted with your calls'
traffic. Each worker waits a random part of those 3 s, so workers that
start together seldom meet at CollieAi. If they do and CollieAi answers
busy, the adapter logs it at INFO and repeats the check 1.5–3 s later, up to twice. A WARNING names what failed:bypass:authfor a wrong key,bypass:not_foundwhen the route is off,bypass:capabilitywhen the project's policy has a rule this beta doesn't run,bypass:transportwhen the server can't be reached,bypass:busywhen CollieAi had no free slot three times in a row. - Within a minute of start, each worker writes a
collieai guardrail summaryline. If there is none, the adapter is not loaded. Look for LiteLLM's ERRORSkipping guardrail(an entry withoutmode), or check whether something set thecollieai_guardraillogger above INFO. - After a test request through the proxy, the summary shows
completedfor both phases. - In operation, compare
eligiblewithlogged_eligible.coverageshows how many checks completed.
Known limits
- The model's reasoning is not checked. A phase that carries reasoning
is outside the supported profile (
outside.reasoning). A reply with reasoning makes post-call outside; pre-call is still checked, unless the request sends earlier replies' reasoning back. If your model always returns reasoning, post-call checks nothing, and itscoverageisnull. - A phase holds at most 32 texts, 4,096 characters each and 16,384 in
all. Pre-call sends the text of every message, the history included, so
a long conversation is bypassed as
limit. These are the limits of the narrow profile, which app.collieai.io runs, and the defaultmax_body_bytesmatches them. A self-hosted CollieAi on the wide profile takes 64 texts and 131,072 characters; setmax_body_bytes: 3211264there. - Counts are per worker process, and they reset when the worker restarts.
- A burst beyond CollieAi's capacity is
busy. Each CollieAi API process checks one call at a time and answers the nextbusy. The adapter counts it as a bypass, and the call goes on unchanged. If the summary shows a lastingbusyshare, tell CollieAi support.
Turning it off
Remove the guardrail entry and reload the proxy. Calls then go on as before.
You can also delete or change the guardrail through LiteLLM's API, without
a reload. A change builds a new instance. The old instance then retires
within summary_interval_s, even if it was deleted right after it was
added:
- it logs one INFO line;
- it stops its summary and synthetic check;
- one deadline later, it closes its connections.
Links
- Documentation: docs.collieai.io/integrations/litellm
- Changelog: CHANGELOG.md
- Security: SECURITY.md
- Contributing: CONTRIBUTING.md
License
Metadata
Release files for collieai-litellm-guardrail 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| collieai_litellm_guardrail-0.1.0.tar.gz | 61.5 kB | With provenance | Details for collieai_litellm_guardrail-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| collieai_litellm_guardrail-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for collieai_litellm_guardrail-0.1.0-py3-none-any.whl |
Total release size: 99.7 kB
Release files / collieai_litellm_guardrail-0.1.0.tar.gz
| Download URL | collieai_litellm_guardrail-0.1.0.tar.gz |
|---|---|
| Size | 61.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
607d38e0b897ecbf865aaed79327634f21b48450d6f779afb8d3382c2648e203
|
|
BLAKE2b-256 checksum How to use checksums |
566913fab21ad9b808388209d5f7cc927a431d2830a01e1389fdec3268371846
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / collieai_litellm_guardrail-0.1.0-py3-none-any.whl
| Download URL | collieai_litellm_guardrail-0.1.0-py3-none-any.whl |
|---|---|
| Size | 38.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ab85a83704a69bf4c6345318f8d05b9f2d9f723ac6def2dc1db02c73dfc6981e
|
|
BLAKE2b-256 checksum How to use checksums |
c108c67913312ac9e83442b6c9f2be8679eae35656d7df7fbdb55f21d66bbbfc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logSecurity for collieai-litellm-guardrail 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for collieai_litellm_guardrail-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.