Install

Three install patterns, one enforced pipeline.

Pick the pattern that fits your codebase. The drop-in proxy is the shortest path: change one line in your SDK constructor, every call now flows through classification, routing, and bounded rehydration. For more control, wrap individual call sites with the decorator or drive the four steps yourself.

Quickstart

Python
pip install runelm
runelm config validate --config runelm.yaml
runelm serve --config runelm.yaml
Docker
docker pull blackunicorn/runelm:latest
docker run -p 8080:8080 \
  -v ./runelm.yaml:/etc/runelm.yaml \
  blackunicorn/runelm:latest
Kubernetes
# hardened Helm chart — non-root,
# read-only rootfs, caps dropped
helm install runelm \
  ./deploy/helm/runelm \
  -f runelm.yaml
Three install patterns

Drop-in proxy first. One line of code.

The headline install is an OpenAI- and Anthropic-compatible HTTP proxy. Swap the SDK’s base_url and every outbound call now flows through Runelm. The other two patterns serve corner cases without changing the guarantee.

Drop-in

OpenAI-compatible proxy

recommended

Run runelm in front of your application. Change one line in the SDK constructor. Every call now flows through classification, routing, and bounded rehydration.

# server side
$ runelm serve --config runelm.yaml

# client side — the only change
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8080/v1",  # <-- swap
    api_key="sk-runelm-...",
)

resp = client.chat.completions.create(
    model="gpt-5",
    messages=[{"role": "user", "content": prompt}],
)
Planned · Phase E

Python decorator

Not yet shipped (Phase E). Wrap the function that calls the LLM. The decorator handles classification, pseudonymization, routing, and rehydration around the call site.

from runelm import runelm_protect, Level

@runelm_protect(session_id="conv-42", min_level=Level.MEDIUM)
def ask_llm(prompt: str) -> str:
    from openai import OpenAI
    client = OpenAI()  # ordinary client, no proxy
    resp = client.chat.completions.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.choices[0].message.content
Planned · Phase E

Direct API

Not yet shipped (Phase E). For custom pipelines. Call classify, pseudonymize, route, and rehydrate yourself.

from runelm import Runelm

rl = Runelm.from_config("runelm.yaml")

result = rl.classify(text=prompt, session_id="conv-42")
sanitized = rl.pseudonymize(result, session_id="conv-42")
provider = rl.route(level=result.level)

# call provider.base_url with sanitized.text
response_text = your_llm_call(sanitized.text, provider)

clean = rl.rehydrate(response_text, session_id="conv-42")

Drop Runelm in front of your LLM client.

One install command. One environment variable. The same provider SDKs you already use. Subscribe below for release notes — new recognizers, threat-model updates, breaking changes.

A BlackUnicorn Security project

A BlackUnicorn Security project

BlackUnicorn Security builds production-grade infrastructure for agentic AI: governance, security, memory, the proxy you are looking at. Runelm is the standalone, MIT-licensed extraction of the sanitization layer.