AI API gateway for protocol translation, inline moderation, streaming parity, and local moderation training.
TransformVetter transforms AI API requests and responses across OpenAI, Claude, and Gemini-compatible formats, then vets request content with keyword rules, smart moderation, local models, and optional LLM review before forwarding upstream.
Note: TransformVetter was previously published as PrismGuard and, earlier, GuardianBraidge.
It is built for production proxy work, not only raw forwarding. The codebase keeps protocol behavior explicit across HTTP routing, request format detection, JSON response conversion, SSE event conversion, moderation error envelopes, history reuse, and training scheduling.
Use it when you need one front door for mixed LLM clients, but still want request moderation before traffic reaches the upstream provider.
Most LLM proxy setups solve either API compatibility or moderation. TransformVetter does both in the same request path:
| Need | What TransformVetter does |
|---|---|
| Mixed client protocols | Accepts OpenAI, Claude, Gemini, and OpenAI Responses-style traffic. |
| Upstream format conversion | Rewrites supported requests and responses into the target API shape. |
| Streaming behavior | Preserves SSE-style streaming while translating deltas and terminal events. |
| Inline safety checks | Runs keyword moderation, profile-based smart moderation, and optional LLM review before forwarding. |
| Local review models | Uses profile-selected local runtimes for confident decisions and falls back when uncertain. |
| Training feedback loop | Stores moderation history and can retrain profile-local models from collected samples. |
[DONE] handling.hashlinear, bow, and fasttext moderation paths selected per profile.TransformVetter is a good fit if you:
It is not designed to be a full API management platform with billing, tenant dashboards, or hosted policy authoring UI.
Use the published container image when you only want to try the proxy:
docker run --rm -p 8000:8000 --env-file .env ghcr.io/cassiopeiacode/transformvetter:latest
curl -s http://127.0.0.1:8000/healthz
Use the release binary when you want a single executable:
gh release download --repo CassiopeiaCode/TransformVetter v1.0.0 --pattern 'TransformVetter-linux-amd64.tar.gz'
tar -xzf TransformVetter-linux-amd64.tar.gz
chmod +x TransformVetter-linux-amd64
./TransformVetter-linux-amd64
The default image is published to GitHub Container Registry:
docker pull ghcr.io/cassiopeiacode/transformvetter:latest
docker run --rm -p 8000:8000 --env-file .env ghcr.io/cassiopeiacode/transformvetter:latest
Common tags:
| Tag | Meaning |
|---|---|
latest |
Latest successful build from the default branch. |
master |
Latest successful build from master. |
sha-<commit> |
Immutable image for a specific commit. |
<version> |
Release image from a v* Git tag, for example 1.2.3. |
Package page:
https://github.com/CassiopeiaCode/TransformVetter/pkgs/container/transformvetter
Tagged releases publish a Linux amd64 binary and checksum:
gh release download --repo CassiopeiaCode/TransformVetter --pattern 'TransformVetter-linux-amd64.tar.gz'
gh release download --repo CassiopeiaCode/TransformVetter --pattern 'TransformVetter-linux-amd64.tar.gz.sha256'
sha256sum -c TransformVetter-linux-amd64.tar.gz.sha256
tar -xzf TransformVetter-linux-amd64.tar.gz
chmod +x TransformVetter-linux-amd64
./TransformVetter-linux-amd64
Release page:
https://github.com/CassiopeiaCode/TransformVetter/releases
git clone https://github.com/CassiopeiaCode/TransformVetter.git
cd TransformVetter
cargo build --release
./target/release/TransformVetter
flowchart LR
Client[Client request] --> Route[Axum route]
Route --> Config[URL or env proxy config]
Config --> Format[format.rs request plan]
Format --> Extract[moderation text extraction]
Extract --> Basic[basic moderation]
Basic --> Smart[smart moderation]
Smart --> Upstream[Upstream LLM API]
Upstream --> Response[JSON response transform]
Upstream --> Stream[SSE stream transcoder]
Response --> Client
Stream --> Client
Smart --> History[(history.rocks)]
History --> Train[train-profile subprocess]
Train --> Model[local model artifacts]
Model --> Smart
Request flow:
{config}${upstream} or !ENV_KEY${upstream}.src/routes.rs parses the proxy configuration and real upstream URL.src/format.rs optionally detects and transforms the request into a target API format.src/moderation/extract.rs derives the text that should be reviewed.basic_moderation can block immediately from keywords.smart_moderation can reuse history, run a local model, or call an LLM reviewer.src/proxy.rs forwards the request to the upstream API only after moderation passes.src/response.rs transforms non-stream JSON responses when needed.src/streaming.rs transcodes SSE streams when the source and target protocols differ.format_transform supports these request format names:
| Format name | API family |
|---|---|
openai_chat |
OpenAI-compatible Chat Completions |
openai_responses |
OpenAI-compatible Responses API |
claude_chat |
Anthropic Claude Messages |
gemini_chat |
Gemini GenerateContent |
The transformation layer handles normal messages, system/instruction fields, multimodal content blocks, tool declarations, tool calls, tool results, stream flags, and path rewrites for target APIs. The response layer includes both JSON conversion and SSE conversion paths, with the broadest coverage in the HTTP proxy and stream tests.
1.89.0.clang and libclang when building dependencies that need native compilation.systemd-run and CPU affinity tools for the scheduler-style workflows.cd TransformVetter
cargo run
By default the service reads .env from the repository root, listens on 0.0.0.0:8000, and exposes:
curl -s http://127.0.0.1:8000/healthz
Expected shape:
{
"ok": true,
"service": "TransformVetter",
"host": "0.0.0.0",
"port": 8000,
"debug": true
}
cargo build --release
./target/release/TransformVetter
The bundled start.sh expects a .env file and a release binary:
nice -n 19 cargo build --release -j 1
./start.sh
docker build -t transformvetter .
docker run --rm -p 8080:8080 transformvetter
The Docker image builds the default feature set. Storage debug routes and sample RPC service code require the explicit storage-debug feature, described below.
The repository uses two publishing workflows.
.github/workflows/ghcr.yml publishes the container image. On every push to master, it builds and pushes:
ghcr.io/cassiopeiacode/transformvetter:latestghcr.io/cassiopeiacode/transformvetter:masterghcr.io/cassiopeiacode/transformvetter:sha-<commit>On v* tags, the same workflow also publishes semver image tags such as :1.2.3, :1.2, and :1.
.github/workflows/release.yml publishes GitHub Releases. On v* tags, it builds a Linux amd64 binary, creates or updates the release, and attaches:
TransformVetter-linux-amd64TransformVetter-linux-amd64.tar.gzTransformVetter-linux-amd64.tar.gz.sha256Manual publishing is available from GitHub Actions:
gh workflow run ghcr.yml --repo CassiopeiaCode/TransformVetter --ref master
gh workflow run release.yml --repo CassiopeiaCode/TransformVetter --ref master -f tag=v1.2.3
TransformVetter does not use a single static upstream route. The proxy route is encoded as:
/{config}${upstream-url}
or, preferably for real deployments:
/!ENV_KEY${upstream-url}
The env form keeps long JSON configs out of client URLs. ENV_KEY must contain JSON.
Example .env entry:
CLAUDE_TO_OPENAI='{"format_transform":{"enabled":true,"strict_parse":true,"from":"claude_chat","to":"openai_chat","delay_stream_header":true},"basic_moderation":{"enabled":true,"keywords_file":"configs/keywords.txt","error_code":"BASIC_MODERATION_BLOCKED"},"smart_moderation":{"enabled":true,"profile":"default"}}'
Example request shape:
curl -sS \
-H 'content-type: application/json' \
-H "authorization: Bearer $UPSTREAM_API_KEY" \
--data '{"model":"claude-3-5-sonnet-latest","max_tokens":64,"messages":[{"role":"user","content":"Hello"}]}' \
'http://127.0.0.1:8000/!CLAUDE_TO_OPENAI$https://api.openai.com/v1/chat/completions'
You can validate config parsing without calling an upstream:
curl -G http://127.0.0.1:8000/debug/url-config \
--data-urlencode 'value=!CLAUDE_TO_OPENAI$https://api.openai.com/v1/chat/completions'
format_transform{
"format_transform": {
"enabled": true,
"strict_parse": true,
"from": "claude_chat",
"to": "openai_chat",
"delay_stream_header": true
}
}
Important fields:
| Field | Meaning |
|---|---|
enabled |
Enables request planning and format conversion. |
strict_parse |
Returns a structured moderation-style error when the source format cannot be detected or is disallowed. |
from |
Source format, array of formats, or auto-style detection when omitted. |
| `to |
$ claude mcp add TransformVetter \
-- python -m otcore.mcp_server <graph>