Standalone Binary
Shield runs as a standalone binary -- no OpenParallax installation required. It exposes a gRPC and REST API for action evaluation and can serve as an MCP security proxy.
Installation
Linux / macOS
curl -sSL https://get.openparallax.dev/shield | shThis installs the openparallax-shield binary to /usr/local/bin/. Supports --version v0.1.0 for pinning and --dir /custom/path for custom install location.
From Source
git clone https://github.com/openparallax/openparallax.git
cd openparallax
make build-shield
# Binary at: dist/openparallax-shieldConfiguration
A default.yaml policy ships alongside the binary in the release archive. Shield uses it automatically when no custom policy is specified, so basic usage requires zero policy configuration.
The policy file can live anywhere -- Shield resolves it from the policy.file path in shield.yaml. By default it looks for default.yaml in the same directory as the binary. To customize:
- Copy
default.yamlto a new file (e.g.my-policy.yaml) - Edit the deny/verify/allow rules to match your environment
- Point
shield.yamlat it:policy.file: my-policy.yaml
Three presets are available in the OpenParallax repository:
- default.yaml -- balanced security (blocks sensitive paths, evaluates shell/external comms at Tier 2, allows workspace reads)
- permissive.yaml -- relaxed rules for development environments
- strict.yaml -- locks down all writes and external communication to Tier 2+
See Policy Syntax for the full rule format and pattern matching reference.
Create a shield.yaml file:
# Shield standalone configuration
# Server settings
listen: localhost:9090
grpc_listen: localhost:9091
# Policy (defaults to default.yaml next to the binary if omitted)
policy:
file: default.yaml
# Classifier
classifier:
model_dir: ~/.openparallax/models/prompt-injection/
threshold: 0.85
# Heuristic engine
heuristic:
enabled: true
# Tier 2 LLM evaluator
evaluator:
provider: anthropic
model: claude-sonnet-4-6
api_key_env: ANTHROPIC_API_KEY
# Security
canary_token: SHIELD-CANARY-a8f3e9b2c4d5e6f7
fail_closed: true
# Rate limiting
rate_limit: 60 # evaluations per minute
daily_budget: 100 # Tier 2 evaluations per day
verdict_ttl: 300 # verdict cache TTL in seconds
# Audit logging
audit:
enabled: true
file: shield-audit.jsonl
# Logging
log_level: info
log_file: shield.logConfiguration Reference
| Field | Type | Default | Description |
|---|---|---|---|
listen | string | localhost:9090 | REST API listen address |
grpc_listen | string | localhost:9091 | gRPC API listen address |
policy.file | string | default.yaml | Path to YAML policy file (bundled default used if omitted) |
classifier.model_dir | string | ~/.openparallax/models/prompt-injection/ | ONNX model directory |
classifier.threshold | float | 0.85 | INJECTION confidence threshold |
heuristic.enabled | bool | true | Enable heuristic pattern matching |
evaluator.provider | string | -- | LLM provider for Tier 2 |
evaluator.model | string | -- | LLM model for Tier 2 |
evaluator.api_key_env | string | -- | Env var for the API key |
evaluator.base_url | string | -- | Custom base URL |
canary_token | string | auto-generated | Token for evaluator injection detection |
fail_closed | bool | true | Block on errors |
rate_limit | int | 60 | Evaluations per minute |
daily_budget | int | 100 | Tier 2 evaluations per day |
verdict_ttl | int | 300 | Verdict cache TTL (seconds) |
audit.enabled | bool | false | Enable audit logging |
audit.file | string | shield-audit.jsonl | Audit log file path |
log_level | string | info | Log level: debug, info, warn, error |
log_file | string | -- | Log file path (stdout if omitted) |
Commands
serve
Start the Shield server:
openparallax-shield serve
openparallax-shield serve --config shield.yaml
openparallax-shield serve --config shield.yaml --port 8080evaluate
Evaluate a single action from the command line:
openparallax-shield evaluate \
--action-type read_file \
--payload '{"path": "/home/user/.ssh/id_rsa"}' \
--config shield.yamlstatus
Show Shield status:
openparallax-shield status --config shield.yamlmcp-proxy
Start Shield as an MCP security proxy:
openparallax-shield mcp-proxy --config shield.yamlSee MCP Gateway for full documentation.
REST API
POST /evaluate
Evaluate an action.
Request:
{
"action_type": "execute_command",
"payload": {
"command": "rm -rf /"
},
"min_tier": 0
}Response:
{
"decision": "BLOCK",
"tier": 1,
"confidence": 0.95,
"reasoning": "heuristic [rm_rf_root, critical]: Recursive root delete detected",
"action_hash": "sha256:a1b2c3d4e5f6...",
"evaluated_at": "2026-04-03T10:30:00Z",
"expires_at": "2026-04-03T10:35:00Z"
}GET /health
Health check.
Response:
{
"status": "ok",
"tier0": true,
"tier1_onnx": true,
"tier1_heuristic": true,
"tier2": true
}GET /status
Shield status including budget usage.
Response:
{
"active": true,
"tier2_enabled": true,
"tier2_used": 42,
"tier2_budget": 100
}Running as a Service
systemd (Linux)
Create /etc/systemd/system/openparallax-shield.service:
[Unit]
Description=OpenParallax Shield - AI Security Pipeline
After=network.target
[Service]
Type=simple
User=shield
Group=shield
WorkingDirectory=/opt/shield
ExecStart=/usr/local/bin/openparallax-shield serve --config /opt/shield/shield.yaml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/opt/shield/logs /opt/shield/audit
PrivateTmp=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
# Resource limits
LimitNOFILE=65536
MemoryMax=2G
# Environment
Environment=ANTHROPIC_API_KEY=
EnvironmentFile=-/opt/shield/.env
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable openparallax-shield
sudo systemctl start openparallax-shield
sudo systemctl status openparallax-shieldlaunchd (macOS)
Create ~/Library/LaunchAgents/dev.openparallax.shield.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>dev.openparallax.shield</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/openparallax-shield</string>
<string>serve</string>
<string>--config</string>
<string>/opt/shield/shield.yaml</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/opt/shield/logs/shield.log</string>
<key>StandardErrorPath</key>
<string>/opt/shield/logs/shield-error.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>ANTHROPIC_API_KEY</key>
<string></string>
</dict>
</dict>
</plist>Load and start:
launchctl load ~/Library/LaunchAgents/dev.openparallax.shield.plistWindows Service
Use sc.exe to register Shield as a Windows service, or use NSSM (Non-Sucking Service Manager) for more control over logging and restart behavior.
Using sc.exe:
sc.exe create OpenParallaxShield `
binPath= "C:\Program Files\OpenParallax\openparallax-shield.exe serve --config C:\shield\shield.yaml" `
start= auto `
DisplayName= "OpenParallax Shield"
sc.exe start OpenParallaxShieldUsing NSSM (recommended for production):
# Install NSSM (via Scoop or download from nssm.cc)
scoop install nssm
# Register the service
nssm install OpenParallaxShield "C:\Program Files\OpenParallax\openparallax-shield.exe"
nssm set OpenParallaxShield AppParameters "serve --config C:\shield\shield.yaml"
nssm set OpenParallaxShield AppDirectory "C:\shield"
nssm set OpenParallaxShield AppStdout "C:\shield\logs\shield.log"
nssm set OpenParallaxShield AppStderr "C:\shield\logs\shield-error.log"
nssm set OpenParallaxShield AppEnvironmentExtra "ANTHROPIC_API_KEY=sk-ant-..."
# Start the service
nssm start OpenParallaxShieldNSSM provides automatic restart on crash, log rotation, and a GUI for editing service parameters (nssm edit OpenParallaxShield).
Docker Deployment
Dockerfile
FROM golang:1.25-alpine AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 make build-shield
FROM alpine:3.20
RUN apk add --no-cache ca-certificates
COPY --from=builder /src/dist/openparallax-shield /usr/local/bin/
COPY security/shield/ /opt/shield/security/shield/
COPY prompts/ /opt/shield/prompts/
WORKDIR /opt/shield
EXPOSE 9090 9091
ENTRYPOINT ["openparallax-shield"]
CMD ["serve", "--config", "/opt/shield/shield.yaml"]Docker Compose
version: '3.8'
services:
shield:
build: .
ports:
- "9090:9090"
- "9091:9091"
volumes:
- ./shield.yaml:/opt/shield/shield.yaml:ro
- ./security/shield:/opt/shield/security/shield:ro
- ./prompts:/opt/shield/prompts:ro
- shield-models:/root/.openparallax/models
- shield-audit:/opt/shield/audit
environment:
- ANTHROPIC_API_KEY
restart: unless-stopped
deploy:
resources:
limits:
memory: 2G
cpus: '2'
volumes:
shield-models:
shield-audit:Monitoring
Prometheus Metrics
Shield exposes metrics at /metrics when running as a standalone server:
# Evaluation counts by tier and decision
shield_evaluations_total{tier="0", decision="BLOCK"} 42
shield_evaluations_total{tier="0", decision="ALLOW"} 1337
shield_evaluations_total{tier="1", decision="BLOCK"} 5
shield_evaluations_total{tier="2", decision="ALLOW"} 28
# Evaluation latency
shield_evaluation_duration_seconds{tier="0"} 0.0001
shield_evaluation_duration_seconds{tier="1"} 0.052
shield_evaluation_duration_seconds{tier="2"} 1.2
# Budget usage
shield_tier2_budget_used 42
shield_tier2_budget_total 100
# Classifier status
shield_classifier_available{type="onnx"} 1
shield_classifier_available{type="heuristic"} 1Health Checks
The /health endpoint returns HTTP 200 when Shield is operational. Use it for load balancer health checks, Kubernetes liveness probes, and Docker health checks:
# Docker Compose
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:9090/health"]
interval: 10s
timeout: 5s
retries: 3# Kubernetes
livenessProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 10
periodSeconds: 10Next Steps
- MCP Gateway -- use Shield as an MCP security proxy
- Configuration -- full configuration reference
- Policy Syntax -- write custom policies