Documentation

Sizing and layers

How much CPU, memory and disk Guard Spec needs, by detection layer. The gateway dominates: its memory is set by which models it loads, and its CPU by how many prompts per second the model layers score. The control plane and Postgres are small next to it.

Choosing layers

DETECTOR_LAYERS picks the layers (one variable, in .env):

Mode DETECTOR_LAYERS Models pulled Use it when
Full (default) l1,l2,l3 classifier + e5 embedder, about 270 MB Production with RAM to spare; L3 matches org-specific exemplars and adds recall on paraphrased attacks
Light l1,l2 classifier only, about 135 MB A laptop, a small VM, a personal setup; about half the memory and 2 to 3 times the throughput of full
Rules only l1 none Very small hosts, or when false positives cost more than missed attacks; much weaker on paraphrases
# quick start in light mode (writes DETECTOR_LAYERS=l1,l2 into the new .env)
DETECTOR_LAYERS=l1,l2 scripts/quickstart.sh
# an existing stack: set DETECTOR_LAYERS=l1,l2 in .env, then
docker compose -f docker-compose.yml up -d

models-init pulls only what the layers need, and /readyz shows the active layers ("layers":["l1","l2"]). What each layer detects and how they are fused: README, Models and Benchmarks.

Measured resource use

Source. Measured on 2026-11-06 by the maintainers on one machine: an Apple M3 Max (arm64) MacBook Pro, Docker Desktop 28.4 with a Linux VM of 14 vCPUs and 15.4 GiB, images ghcr.io/guard-spec/guard-spec-gateway:0.1.0 (linux/arm64) and -control-plane:0.1.0, models guardspec-classifier@v3b and multilingual-e5-small@614241f. Memory and CPU are docker stats (sampled about once a second during the run; CPU 100% = one core). Load is ApacheBench, 8 concurrent clients, POST /v1/chat/completions with a system message and a 350-character user prompt, the stub upstream (no UPSTREAM_LLM_URL), so the numbers are the guard's own cost; every request also writes an audit row. Other hardware, x86-64 CPUs in particular, will differ: measure on yours (below) before you size a fleet.

Unconstrained (quick start, no limits)

The gateway may use all 14 vCPUs; INFERENCE_MAX_CONCURRENCY defaults to the CPU count (14) and ORT uses 4 threads per run.

Layers Gateway RAM idle Gateway RAM peak Gateway CPU under load (mean / peak) Requests/s Latency p50 / p95 / p99
L1 10 MiB 28 MiB 2.9 / 4.0 cores 1,784 3 / 6 / 13 ms
L1 + L2 483 MiB 511 MiB 9.3 / 10.1 cores 387 19 / 31 / 43 ms
L1 + L2 + L3 909 MiB 942 MiB 12.9 / 15.6 cores 137 53 / 103 / 152 ms

With the production compose limits

deploy/compose/production defaults: gateway limited to 2 CPUs and 2 GiB, INFERENCE_MAX_CONCURRENCY=2, INFERENCE_INTRA_OP_THREADS=1; load sent from inside the compose network straight to the gateway.

Layers Gateway RAM idle Gateway RAM peak Gateway CPU under load Requests/s Latency p50 / p95 / p99
L1 11 MiB 22 MiB 1.5 cores 2,168 2 / 9 / 23 ms
L1 + L2 481 MiB 503 MiB 1.9 cores 118 68 / 74 / 79 ms
L1 + L2 + L3 904 MiB 909 MiB 1.9 cores 55 138 / 166 / 288 ms

With 8 clients and 2 model runs at a time, most of that latency is queueing: one scan takes about 2 / throughput (17 ms light, 36 ms full on this CPU).

The other services

Service RAM CPU
Control plane about 10 MiB, idle and under gateway load under 1%
Postgres 42 to 66 MiB idle, up to 100 MiB under the loads above 0.3 cores at 137 audit writes/s, 0.6 at 387, 1.8 at 1,784
Caddy (production compose) up to 17 MiB small

Recommendations

Starting points, from the tables above plus headroom. Only the "small team" row matches a measured configuration; the others are extrapolated from it. Requests/s are the guard alone; your upstream LLM's latency comes on top and does not use the gateway's CPU while it waits.

Setup Layers Host Gateway limit Roughly handles
Personal / laptop l1,l2 2 vCPU, 2 GB RAM free none tens of requests/s
Small team, one VM l1,l2 2 vCPU, 4 GB 2 CPUs, 1 GiB about 100 requests/s
Startup production, one VM l1,l2,l3 4 vCPU, 8 GB 2 to 3 CPUs, 2 GiB about 50 to 80 requests/s
More traffic l1,l2,l3 several gateway replicas (Kubernetes, Helm chart) 2 CPUs, 2 GiB each add replicas; throughput scales with cores

Disk

Measure on your hardware

# 1. a key (see the README quick start), then a body like your traffic
cat > body.json <<'EOF'
{"model":"m","messages":[{"role":"user","content":"<a prompt of typical length>"}]}
EOF
# 2. load, while watching the containers
ab -n 5000 -c 8 -p body.json -T application/json -H "x-api-key: $KEY" \
  http://localhost:8080/v1/chat/completions
docker stats    # in another terminal
# 3. audit table size per row
docker compose exec postgres psql -U ps -d guardspec -c \
  "SELECT count(*), pg_size_pretty(pg_total_relation_size('requests')) FROM requests"

Run it without UPSTREAM_LLM_URL (stub answers) to see the guard alone, and once per DETECTOR_LAYERS value you consider. Reports with other hardware are welcome in an issue.

Source: docs/sizing.md @ ca69dad29f02