WeeBie is a self-hosted AI firewall and monitoring platform that sits between your enterprise's people, apps, and every AI model they use — governing, monitoring, and protecting every AI interaction.
WeeBie bundles proven enterprise-grade observability, agent-safety, and logging technology into a single system with one dashboard and one API — professionally deployed on hardware you already own. Nothing leaves your network unless you explicitly allow it.
Stand up an evaluation instance to explore WeeBie hands-on.
Start here →Full network integration guide for medium-to-large organizations.
Deploy in production →Complete REST API docs for the control plane and OpenAI-compatible gateway.
Browse the API →The OpenAI-compatible proxy that makes WeeBie a true AI firewall.
How it works →| Capability | What It Does | Section |
|---|---|---|
| Full Observability | Traces, metrics, dashboards for every AI call | View → |
| Guardrails & DLP | Detect & redact PII, block banned terms | View → |
| Approval Workflow | Hold risky AI actions for human sign-off | View → |
| Drift Detection | Detect when AI behavior changes over time | View → |
| Cost Metering | Track AI spend by model, team, and day | View → |
| AI Gateway | OpenAI-compatible proxy with virtual keys | View → |
| Tamper-Evident Audit | SHA-256 hash-chained compliance log | View → |
| Multi-Tenant & RBAC | Per-tenant isolation, custom fine-grained roles | View → |
| AI Threat Protection | Prompt-injection, jailbreak, secret-leak & exfiltration detection | View → |
| Provider Failover | Fallback chains, retries, circuit breaker | View → |
| Enterprise IAM | SCIM 2.0, SAML sign-in, key expiry & rotation | View → |
| SIEM & Log Export | Stream/pull audit events to Splunk, Datadog, Elastic (JSON/CEF) | View → |
| Data Governance | Retention/purge, GDPR erasure, data-residency routing | View → |
| Evaluation & Quality | Golden-set eval suites + CI regression gating | View → |
| FinOps Chargeback | Cost-center allocation, anomaly alerts, hard quotas | View → |
| Multimodal Gateway | Embeddings & image generation through the firewall | View → |
| Bedrock & Vertex | Native AWS Bedrock (SigV4) & Google Vertex adapters | View → |
| SDKs & Terraform | Python/JS/Go/Java/.NET SDKs, Terraform provider, LangChain/LlamaIndex | View → |
| Backups & DR | Automated nightly backups, encrypted off-box copy, tested restore + one-box drill | View → |
WeeBie deploys as a single server (VM or bare metal) running Docker Compose. It sits in your network between your users and the AI providers they call. Your firewall blocks direct AI API egress, forcing all AI traffic through WeeBie — making it a true firewall, not just a proxy.
Stand up an evaluation instance of WeeBie on a Linux server with Docker. This guide is for hands-on evaluation and testing.
If Docker isn't installed yet:
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
# Log out and back in for the group change
tar xzf weebie-install-package.tar.gz
cd weebie
You'll receive the complete installation package from WeeBie after licensing.
cp .env.example .env
nano .env
Set the critical values:
UAMCS_ENV=production
BRAND_NAME=WeeBie
GATEWAY_DOMAIN=your-domain
CONTROL_PLANE_API_KEYS=$(openssl rand -hex 24)
AUTH_SECRET=$(openssl rand -hex 32)
AUTH_REQUIRE_LOGIN=true
UAMCS_ADMIN_USER=admin
UAMCS_ADMIN_PASSWORD=<set-a-strong-password>
docker compose up -d
This starts the lean core (~2 GB RAM). First run downloads images and takes 2-3 minutes.
# Health check
curl https://your-domain/health
# → {"status":"ok","env":"production"}
# Open the dashboard
open https://your-domain
Sign in with admin / <your-password> from your .env.
docker compose --profile llm up -d
# Pull a small model for testing:
docker exec the-llm-container pull-model llama3.2:1b
docker compose --profile prompts up -d
This starts the prompt versioning module for advanced cost tracking.
docker-compose.yml.
Understand how WeeBie is structured, what each component does, and how data flows through the system.
Every feature in WeeBie is optimized against three goals:
Know what your AI is spending — and stop the waste. Per-model, per-team, per-day tracking.
Prevent data leaks, block rogue AI actions, stay compliant with tamper-evident audit.
Make AI faster, more reliable, better quality. Catch drift, get optimization suggestions.
The Control Plane is the "glue" — the part we build. It's a FastAPI application that provides the unified API, runs the guardrails, policy engine, drift detection, cost ledger, audit chain, approval queue, and the OpenAI-compatible gateway. It's a modular monolith: internally modular (each capability is its own module with a clean interface), but deployed as one process.
The AI Gateway is the product centerpiece. It's an OpenAI-compatible
proxy endpoint at /v1/chat/completions. Any app that
speaks the OpenAI API can point at WeeBie by changing one line — the
base URL. The gateway then:
Instead of giving teams the real OpenAI/Anthropic API key, WeeBie
issues virtual keys (uamcs-...). These
map to real provider keys held gateway-side. Virtual keys support
per-team budgets (auto-block at limit → HTTP 402), instant revoke,
and per-tenant isolation. This is a major enterprise selling point —
it centralizes and rotates real keys.
| Mode | What the customer does | Bypass resistance |
|---|---|---|
| A — Drop-in gateway | Change base_url to WeeBie | Medium (opt-in) |
| B — Network egress enforcement | Firewall blocks direct AI egress; only WeeBie may reach providers | High |
| C — Thin SDK | pip install weebie / npm i @weebie/sdk; wrap the LLM client | Medium (opt-in) |
Mode A is the product. Mode B is what makes it a firewall. Mode C is the developer-friendly on-ramp. Same core, three front doors.
| Component | Role | License |
|---|---|---|
| TLS Edge | TLS termination / reverse proxy | Commercial |
| Database | Primary database (audit, users, drift, cost) | Commercial |
| Metrics Engine | Metrics store + alerting | Commercial |
| Tracing Engine | Distributed tracing | Commercial |
| Dashboard Engine | Metrics visualization | Commercial |
| Telemetry Pipeline | Telemetry collection and routing | Commercial |
| Alert Router | Alert routing (Slack, email) | Commercial |
| Object Storage | S3-compatible object storage (audit mirror) | Commercial |
| Prompt Manager | Prompt versioning + cost tracking | Commercial |
| Local LLM Engine | Local LLM inference (offline AI) | Commercial |
Hardware and software requirements for running WeeBie in production.
| Resource | Specification |
|---|---|
| CPU | 2 vCPU (x86_64) |
| RAM | 4 GB |
| Disk | 40 GB SSD |
| OS | Ubuntu 22.04 LTS or 24.04 LTS |
| Network | 1 Gbps NIC, static IP recommended |
| GPU | Not required |
Runs: TLS Edge, Control Plane, Dashboard, Database, Metrics, Tracing, Dashboard Engine, Telemetry, Alert Router, Object Storage. Total memory usage ~2 GB.
| Resource | Specification |
|---|---|
| CPU | 4+ vCPU |
| RAM | 8-16 GB |
| Disk | 80 GB SSD |
| GPU | Optional: NVIDIA GPU for local LLM inference. Without GPU, the local LLM runs on CPU (slower but functional). |
| Resource | Specification |
|---|---|
| WeeBie nodes | 2+ (load balanced) |
| Database | Dedicated VM (HA database or managed RDS) |
| RAM per node | 8+ GB |
| Disk | 100+ GB SSD per node |
| Backup | Off-host backup storage (S3, NFS, or cloud) |
# Required on the WeeBie server:
- Docker Engine 24.0+
- Docker Compose v2.20+
- curl, git, openssl
# All other software (TLS edge, database, metrics, etc.)
# runs inside Docker containers — no host-level installation needed.
127.0.0.1 by default.
Only the TLS Edge is publicly exposed. Admin access to
internal services is via SSH tunnel. Never bind internal services
to 0.0.0.0 in production.
Complete step-by-step installation of WeeBie on a fresh Linux server.
ssh admin@your-server-ip
# Update the OS
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
# Log out and back in for the group change to take effect
# Verify
docker --version
docker compose version
WeeBie is distributed as a versioned release bundle (current: v1.4.0) — you will receive it directly from WeeBie after purchasing a license, with a SHA-256 checksum and file manifest. It comes in two editions: standard (compact — container images are digest-pinned and pulled from public registries during install) and air-gapped (self-contained — every container image and a local LLM model included; see the Air-Gapped Installation section). If you prefer, WeeBie also offers professional installation services — our team will deploy and configure everything for you.
# Create the installation directory
sudo mkdir -p /opt/your-install-dir
sudo chown $USER:$USER /opt/your-install-dir
cd /opt/your-install-dir
# Verify and extract the release bundle
sha256sum -c weebie-monitor-1.4.0.tar.gz.sha256
tar xzf weebie-monitor-1.4.0.tar.gz && cd weebie-monitor-1.4.0
# One-command install — performs Steps 4-6 for you (secrets, config,
# start, acceptance smoke test) and prints the URLs + admin login once:
bash scripts/install.sh --domain ai.yourcompany.com --yes
# Prefer manual control? The steps below walk the same process by hand.
cp .env.example .env
# Generate secure secrets
openssl rand -hex 24 # → CONTROL_PLANE_API_KEYS
openssl rand -hex 32 # → AUTH_SECRET
nano .env
Set these critical values:
UAMCS_ENV=production
BRAND_NAME=WeeBie
GATEWAY_DOMAIN=ai.yourcompany.com
CONTROL_PLANE_API_KEYS=<generated-key>
AUTH_SECRET=<generated-secret>
AUTH_REQUIRE_LOGIN=true
UAMCS_ADMIN_USER=admin
UAMCS_ADMIN_PASSWORD=<strong-password>
POSTGRES_PASSWORD=<strong-password>
# AI providers (optional at install time, configure later)
GATEWAY_PROVIDERS={"openai":{"base_url":"https://api.openai.com/v1","api_key":"sk-...","models":["gpt-4o"]}}
# Enforcement
GATEWAY_ENFORCE=true
gateway_log_content=false
# CORS (set to your dashboard URL)
CORS_ALLOW_ORIGINS=https://ai.yourcompany.com
# Lean core (recommended first start)
docker compose up -d
# With local LLM
docker compose --profile llm up -d
# Everything (includes prompt versioning)
docker compose --profile full up -d
# Check containers
docker compose ps
# Health check
curl https://your-domain/health
# → {"status":"ok","env":"production"}
# Gateway
curl -H "X-API-Key: *** https://your-domain/v1/models
# Dashboard (in browser)
# https://your-domain
Sign in with the admin credentials from .env, then
immediately change the password: Settings → Your account →
Change password.
.env file.
Anyone who reads that file knows your password. Change it
through the dashboard after first login.
How to deploy WeeBie into a medium enterprise network: firewall → core switch → access switch → end devices.
| VLAN | Subnet | Purpose | WeeBie IP |
|---|---|---|---|
| VLAN 10 | your-internal-subnet | Servers | your-server-ip |
| VLAN 20 | your-employee-vlan | Employees | — |
| VLAN 30 | your-admin-vlan | IT / Admin | — |
# EGRESS: Block all direct AI API egress from internal VLANs
DENY SRC=your-employee-vlan DST=api.openai.com PORT=443
DENY SRC=your-employee-vlan DST=api.anthropic.com PORT=443
DENY SRC=your-admin-vlan DST=api.openai.com PORT=443
DENY SRC=your-admin-vlan DST=api.anthropic.com PORT=443
# EGRESS: Allow WeeBie server to reach AI providers
ALLOW SRC=your-weebie-ip DST=any PORT=443
# INGRESS: Allow internal VLANs to reach WeeBie
ALLOW SRC=your-employee-vlan DST=your-weebie-ip PORT=443
ALLOW SRC=your-admin-vlan DST=your-weebie-ip PORT=443
# INGRESS: Block external access (unless using public endpoint)
DENY SRC=any DST=your-weebie-ip PORT=443
# In your internal DNS server:
ai.corp.local A your-server-ip # WeeBie server
# Alternative: split-horizon DNS (transparent interception)
api.openai.com A your-server-ip # → WeeBie (apps don't need config changes)
Best for up to ~500 AI users. All 12 containers run on one VM.
# One VM, one command:
docker compose up -d
Best for 500+ users, compliance, or HA needs.
# WeeBie VM (your-server-ip) — app layer
# Database VM (db-server-ip) — data layer
# Observability VM (obs-server-ip) — telemetry
# .env overrides:
POSTGRES_HOST=db-server-ip
METRICS_URL=http://obs-server-ip:9090
TRACING_URL=http://obs-server-ip:16686
helm install weebie ./deploy/helm/weebie \
--set gateway.domain=ai.corp.local \
--set ingress.enabled=true
See the Air-Gapped Install section.
No software is installed on end devices. Only a configuration change:
# Before (direct to OpenAI):
client = OpenAI(base_url="https://api.openai.com/v1", api_key="sk-...")
# After (through WeeBie):
client = OpenAI(base_url="https://ai.corp.local/v1", api_key="uamcs-team-key-...")
| Method | How It Works |
|---|---|
| Always-on VPN | Laptop connects to VPN → all AI traffic routes through WeeBie automatically. No WeeBie-specific config needed. |
| SASE / SSE | Zscaler/Netskope/Cloudflare → SASE policy redirects AI API calls to WeeBie's public endpoint. No agent on the laptop. |
| MDM-pushed proxy | Intune/Jamf pushes a PAC file or proxy config → AI calls route to WeeBie over public TLS. |
| Public TLS endpoint | WeeBie is exposed on a public domain (e.g., weebie.company.com) with login + virtual keys protecting access. |
base_url changed to point at WeeBie. The
firewall enforces that they can't bypass it.
Deploy WeeBie with zero internet access. All data stays on your hardware. Ideal for regulated industries, government, and defense.
WeeBie can run fully offline. The air-gap egress lock
(UAMCS_AIRGAPPED=true) blocks any outbound call to
non-allowlisted hosts. All 12 containers run locally. The local LLM provides
local LLM inference without needing cloud AI providers.
WeeBie's air-gap edition (weebie-monitor-1.4.0-airgap.tar.gz,
~5.5 GB) is fully self-contained: every container image, a pre-pulled local
LLM model (llama3.2:1b), and the offline install steps
(airgap-images/LOAD-ME.md). No internet is needed at any point on the
target machine — this exact flow is verified by a zero-internet install drill.
# Copy via USB, approved transfer station, etc. Then on the air-gapped server:
sha256sum -c weebie-monitor-1.4.0-airgap.tar.gz.sha256
tar xzf weebie-monitor-1.4.0-airgap.tar.gz
cd weebie-monitor-1.4.0-airgap
# Load every container image (no pulling, no network)
docker load -i airgap-images/images.tar
# Restore the pre-pulled LLM model into the volume the stack uses
docker volume create uamcs_ollamadata
docker run --rm -v uamcs_ollamadata:/data -v "$PWD/airgap-images:/src" \
postgres:16-alpine tar xzf /src/ollama-model.tar.gz -C /data
# Generate all secrets/config locally (no network involved)
bash scripts/install.sh --yes --config-only
# Start with the air-gap overrides — never pulls, enables the egress lock,
# and routes the AI gateway to the bundled local LLM out of the box:
docker compose -f docker-compose.yml -f docker-compose.airgap.yml \
--profile llm up -d --no-build
# Verify the air gap is active:
curl localhost:8080/health
# → {"status":"ok", ..., "airgapped":true}
When air-gap is enabled, only these Docker-network hosts are reachable:
| Host | Service |
|---|---|
localhost | Local services |
local-llm | Local LLM inference |
database | Database |
tracing | Tracing |
metrics | Metrics |
dashboards | Dashboards |
alerts | Alerts |
telemetry | Telemetry |
object-storage | Object storage |
prompt-mgr | Prompt versioning |
keycloak | OIDC (if used) |
To add a custom internal MCP server or service, add its hostname to _ALLOWED_INTERNAL_HOSTS in control-plane/app/security.py.
docker exec the-control-plane-container python3 -c "
from app.security import assert_egress_allowed
# External → BLOCKED
try: assert_egress_allowed('http://api.openai.com/v1')
except: print('BLOCKED ✓')
# Internal → ALLOWED
assert_egress_allowed('http://your-local-llm:port/v1')
print('ALLOWED ✓')
"
How WeeBie handles HTTPS, certificates, and the public TLS edge.
The TLS Edge is the public-facing edge of WeeBie. It terminates TLS, applies security headers, and reverse-proxies to the internal services. Only the TLS Edge is exposed to the network; everything else runs on the private Docker network.
{$GATEWAY_DOMAIN} {
# AI gateway — OpenAI-compatible
handle /v1/* {
reverse_proxy control-plane:8080
}
# Everything else → dashboard (login required)
reverse_proxy dashboard:3000
encode gzip
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
}
# www → apex redirect
www.{$GATEWAY_DOMAIN} {
redir https://{$GATEWAY_DOMAIN}{uri} permanent
}
The TLS Edge provisions certificates automatically:
ai.company.com): Let's Encrypt certificate. DNS must point to the server. Ports 80 + 443 must be open.ai.corp.local): The internal CA generates a self-signed cert. Distribute the root cert to end devices via GPO/MDM.# Extract the CA cert from the TLS Edge container
docker cp the-edge-container:/data/edge/pki/authorities/local/root.crt \
/tmp/weebie-ca.crt
# Distribute via GPO (Windows):
# Group Policy → Computer Configuration → Policies →
# Windows Settings → Security Settings → Public Key Policies →
# Trusted Root Certification Authorities → Import
# Distribute via Jamf (macOS):
# Configuration Profile → Certificates → Root Certificate
The TLS Edge applies these headers automatically:
| Header | Value | Purpose |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Force HTTPS for 1 year |
X-Content-Type-Options | nosniff | Prevent MIME sniffing |
X-Frame-Options | DENY | Prevent clickjacking |
Referrer-Policy | strict-origin-when-cross-origin | Limit referrer leakage |
Server | (removed) | Hide server identity |
How to configure WeeBie to route AI requests to OpenAI, Anthropic, Azure, local LLM, or any OpenAI-compatible provider.
WeeBie holds the real API keys for each provider. Users/apps never
see these keys — they get virtual keys (uamcs-...) instead.
When a request comes in with a model name like gpt-4o,
WeeBie routes it to the matching provider.
Set GATEWAY_PROVIDERS in .env as a JSON object:
GATEWAY_PROVIDERS={
"openai": {
"base_url": "https://api.openai.com/v1",
"api_key": "sk-proj-xxxxx",
"models": ["gpt-4o", "gpt-4o-mini", "gpt-4.1", "o1"]
},
"anthropic": {
"base_url": "https://api.anthropic.com/v1",
"api_key": "sk-ant-xxxxx",
"models": ["claude-opus", "claude-sonnet", "claude-haiku"]
},
"local": {
"base_url": "http://your-local-llm:port/v1",
"api_key": "",
"models": ["llama3.2:1b"]
}
}
Apps specify the model name in their request — WeeBie routes automatically:
# Python — routed to OpenAI
client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}]
)
# Routed to Anthropic
client.chat.completions.create(
model="claude-sonnet",
messages=[{"role": "user", "content": "Hello"}]
)
# Routed to local LLM ($0 cost)
client.chat.completions.create(
model="llama3.2:1b",
messages=[{"role": "user", "content": "Hello"}]
)
You can also use a provider/model prefix for explicit routing:
model="openai/gpt-4o" # → OpenAI
model="anthropic/claude-sonnet" # → Anthropic
model="local/llama3.2:1b" # → Local LLM
Virtual keys are created in the dashboard (Settings → Team access keys) or via the API. Each key can have a monthly budget. Hitting the budget returns HTTP 402. Keys can be revoked instantly.
# Create a virtual key via API
curl -X POST -H "X-API-Key: $SERVICE_KEY" \
-H "Content-Type: application/json" \
-d '{"label":"Engineering Team","budget_monthly":500.00}' \
https://your-domain/api/v1/vkeys
# → {"id":1,"key":"uamcs-AbCdEf...","key_prefix":"uamcs-AbCd..."}
# Use it instead of the real OpenAI key:
client = OpenAI(base_url="https://ai.corp.local/v1",
api_key="uamcs-AbCdEf...")
| Provider | Base URL | Notes |
|---|---|---|
| OpenAI | https://api.openai.com/v1 | Full support including streaming |
| Anthropic | https://api.anthropic.com/v1 | OpenAI-compatible mode |
| Azure OpenAI | https://your-resource.openai.azure.com | Use deployment name as model |
| Google Gemini | https://generativelanguage.googleapis.com/v1beta/openai | OpenAI-compatible endpoint |
| Local LLM (on-prem) | http://your-local-llm:port/v1 | Free, offline, $0 cost |
| vLLM | http://your-vllm:8000/v1 | Self-hosted model serving |
| LM Studio | http://your-local-llm:port/v1 | Local desktop inference |
How WeeBie authenticates users and controls access with role-based permissions.
WeeBie supports dual authentication:
X-API-Key header) — for services and machine-to-machine auth. Service keys bypass RBAC (trusted).Authorization: Bearer header) — for human users via Keycloak, Entra ID, ADFS, or local accounts.| Role | Can Do |
|---|---|
| Viewer | See everything, change nothing |
| Editor | Viewer + manage prompts |
| Approver | Viewer + approve/deny held AI actions |
| Admin | Everything: policy, guardrails, users, keys, data |
| Service | API key only — bypasses RBAC (machine credentials) |
WeeBie has built-in user accounts stored in its database. Passwords are hashed with PBKDF2. No external IdP needed for small deployments.
# Create a user
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"username":"alice","password":"strong-pass","role":"viewer"}' \
https://your-domain/api/v1/users
# Login (get JWT)
curl -X POST -H "Content-Type: application/json" \
-d '{"username":"alice","password":"strong-pass"}' \
https://your-domain/api/v1/auth/login
# → {"access_token":"eyJ...","role":"viewer","tenant":"default"}
For Active Directory / enterprise SSO, set these in .env:
AUTH_KEYCLOAK_ISSUER=https://keycloak.corp.local/realms/corp
AUTH_KEYCLOAK_ID=weebie-dashboard
AUTH_KEYCLOAK_SECRET=<client-secret>
# AD groups → roles via claim mapping:
OIDC_ROLES_CLAIM=realm_access.roles
OIDC_TENANT_CLAIM=tenant
5 failed login attempts = 15-minute lock on that account. The lock clears automatically. This is the brute-force throttle, not a bug.
RBAC is enforced at two levels:
require_role(...) gates sensitive mutations. The real enforcement point.See every step your AI takes — live dashboards for cost, speed, errors, and usage, like a flight recorder for every AI interaction.
| Page | What It Shows |
|---|---|
| Overview | Live health summary, recent activity, items needing approval |
| Observability | Live charts: request volume, latency, error rates. Click a chart to drill into traces. |
| Alerts | Firing alerts + audited history. Severity levels: critical, warning, info. |
| Optimize | Ranked suggestions for endpoints that are slow, erroring, or costing too much. |
# Dashboard data
GET /api/v1/observe/dashboard
GET /api/v1/observe/metrics
GET /api/v1/observe/metrics/range?start=...&end=...
GET /api/v1/observe/endpoints
GET /api/v1/observe/services
# Optimization suggestions
GET /api/v1/observe/optimize
# Alerts
GET /api/v1/observe/alerts
# Metrics (scraped by metrics engine)
GET /metrics
Use the example script examples/instrument_your_app.py to
add distributed tracing to your AI apps. Send traces via OTLP to
http://weebie:4317.
Automatically catch or hide sensitive data — emails, card numbers, SSNs. Block banned words. Cap response length. All enforced inline, in real time.
| Rule | What It Detects | Action |
|---|---|---|
pii:email | Email addresses | Flag or redact → [REDACTED_EMAIL] |
pii:ssn | Social Security numbers | Flag or redact → [REDACTED_SSN] |
pii:credit_card | Credit card numbers | Flag or redact → [REDACTED_CREDIT_CARD] |
pii:ipv4 | IPv4 addresses | Flag or redact |
banned_term | Configured banned words | Block the request |
max_length | Response exceeds length cap | Flag / truncate |
For richer checks (toxic language, competitor mentions, JSON validity),
install the optional advanced-validators package. This requires
internet at setup and is off by default for air-gap compatibility.
# Validate text for PII
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"text":"Contact me at john@example.com","redact":true}' \
https://your-domain/api/v1/guardrails/validate
# Response:
{
"passed": false,
"violations": [{"rule": "pii:email", "message": "detected email"}],
"redacted_text": "Contact me at [REDACTED_EMAIL]"
}
# View current config
GET /api/v1/guardrails/config
# → {"block_pii": true, "redact": true, "banned_terms": ["confidential"], ...}
# Update config
POST /api/v1/guardrails/config
{
"block_pii": true,
"redact": true,
"banned_terms": ["confidential", "internal", "secret"],
"max_length": 4096
}
When GATEWAY_ENFORCE=true, guardrails are applied
in-path — every request and response through the
gateway is scanned. PII is redacted before the request reaches the
AI provider, and before the response reaches the user.
GET /api/v1/guardrails/violations
# → List of all violations with timestamps, rules hit, and (optionally) samples.
# Content samples are NOT logged by default (privacy) — only the rule + metadata.
Risky AI actions — sending emails, running shell commands, deleting data — are held for human sign-off before they execute. You approve or deny with one click.
| Level | Behavior | Examples |
|---|---|---|
| Allow | Auto-approved, executed immediately | read_file, search |
| High-risk | Held for human approval | send_email, shell, delete |
| Blocked | Auto-denied, not on allowlist | delete_file, unknown tools |
# Submit a risky action for approval
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"tool":"send_email","arguments":{"to":"ceo@corp.com"},"actor":"agent:bot"}' \
https://your-domain/api/v1/approvals/submit
# → {"decision":"require_approval","approval_id":3,"status":"pending"}
# List pending approvals
GET /api/v1/approvals?status=pending
# Approve
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"decision":"approve","decided_by":"admin","note":"OK"}' \
https://your-domain/api/v1/approvals/3/decide
# Deny
curl -X POST -H "X-API-Key: *** -H "Content-Type: application/json" \
-d '{"decision":"deny","decided_by":"admin","note":"too risky"}' \
https://your-domain/api/v1/approvals/3/decide
Only approver or admin roles can approve/deny. Viewers can see the queue but cannot decide.
Get warned when your AI's behavior changes over time — slower responses, quality shifts, unusual patterns. Industry-standard PSI metrics, fully offline.
Population Stability Index (PSI) is an industry-standard drift metric. It compares a known-good baseline distribution against current data:
| PSI | Meaning |
|---|---|
| < 0.1 | No significant drift OK |
| 0.1 – 0.25 | Moderate drift — investigate Warn |
| > 0.25 | Significant drift — alert Alert |
# Create a baseline
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"metric":"response_latency","values":[0.2,0.22,0.21,...],"bins":10}' \
https://your-domain/api/v1/drift/baselines
# Evaluate with current data
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"metric":"response_latency","current":[0.8,0.9,0.85,...]}' \
https://your-domain/api/v1/drift/evaluate
# → {"psi":12.10,"severity":"significant","drifted":true}
# List baselines (shows last PSI + severity)
GET /api/v1/drift/baselines
# Stateless PSI check (pass both samples)
POST /api/v1/drift/psi
Alert rules in config/alerts.yml:
DriftModerate ≥ 0.1, DriftSignificant ≥ 0.25.
The alert router routes to the control plane webhook, which writes each
alert to the audit chain — so drift alerts are part of your compliance
trail, not just a transient ping.
Track real AI spending by day, by model, by team. Local models show $0. Cloud models show real dollars. No more surprise bills.
Every request through the gateway is automatically metered. WeeBie records the model, input/output tokens, and calculates cost from a built-in pricing table. The cost ledger stores events and provides aggregation queries.
GET /api/v1/cost/pricing
# → 16 models with input/output rates per 1K tokens:
# gpt-4o: $0.0025 in / $0.01 out
# claude-sonnet: $0.003 in / $0.015 out
# local: $0.00 (local)
# ...
# Cost ledger (daily summary)
GET /api/v1/cost/ledger?days=7
# → {"total_cost":12.50,"tokens":{"input":50000,"output":30000},
# "by_model":[{"model":"gpt-4o","cost":10.00,...}],
# "by_endpoint":[...],"daily":[...]}
# Record a manual cost event
POST /api/v1/cost/record
{"model":"gpt-4o","input_tokens":500,"output_tokens":500,
"endpoint":"/v1/chat/completions","actor":"user:alice"}
# Cost summary (from observability data)
GET /api/v1/cost/summary?days=30
Virtual keys can carry a monthly budget. When the budget is hit, requests return HTTP 402 Payment Required until the month rolls over or an admin raises the budget.
# Create a key with $500/month budget
POST /api/v1/vkeys
{"label":"Engineering","budget_monthly":500.00}
The OpenAI-compatible proxy that makes WeeBie a true AI firewall. Point any OpenAI-compatible app at WeeBie by changing one line.
The gateway speaks the full OpenAI API:
| Endpoint | Method | Description |
|---|---|---|
/v1/models | GET | List available models |
/v1/chat/completions | POST | Chat completion (streaming + non-streaming) |
/v1/embeddings | POST | Text embeddings (if provider supports) |
# Non-streaming
curl -X POST -H "X-API-Key: uamcs-..." -H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello"}],"max_tokens":10}' \
https://ai.corp.local/v1/chat/completions
# Streaming (SSE)
curl -N -X POST -H "X-API-Key: uamcs-..." -H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hi"}],"stream":true}' \
https://ai.corp.local/v1/chat/completions
provider/model prefix| Mode | GATEWAY_ENFORCE | Behavior |
|---|---|---|
| Observe | false | Logs everything, blocks nothing. Good for Phase 1 pilots. |
| Enforce | true | Blocks PII, redacts sensitive data, holds risky actions. Production mode. |
Every AI action, approval, and decision is recorded in a SHA-256 hash chain that can't be silently edited or erased. Compliance-ready, verified with one API call.
Each audit record contains a hash field computed from
its content + the previous record's hash. This creates a chain where
modifying any record breaks the hash of that record and every
subsequent record.
# Verify chain integrity
GET /api/v1/audit/verify
# → {"intact": true, "first_broken_seq": null}
# Export all records
GET /api/v1/audit/export
# → {"records": [{"seq":0,"action":"deploy_verify","hash":"...","prev_hash":"..."}, ...]}
# Append a custom audit record
POST /api/v1/audit/append
{"action":"manual_review","actor":"admin","timestamp":"2026-07-06T12:00:00Z"}
# Query records
GET /api/v1/audit/records?limit=20
| Action | Trigger |
|---|---|
llm_request | Every gateway call (chat completion) |
guardrail_violation | When guardrails block/redact content |
approval_requested | Risky action submitted for approval |
action_allow | Approval granted |
action_deny | Approval denied |
vkey_created / vkey_revoked | Virtual key lifecycle |
drift_alert | Drift detection triggers an alert |
deploy_verify | System deployment verification |
Each tenant has its own independent hash chain — separate seq,
separate prev_hash. Tampering with one tenant's chain
doesn't affect another's.
Audit records are also mirrored to object storage (S3-compatible storage), providing a second copy that survives even if the database is compromised.
Serve multiple teams from one deployment with full data isolation. Role-based access: admin, approver, editor, viewer.
Every authenticated principal carries a tenant ID:
key:tenant format in CONTROL_PLANE_API_KEYS.OIDC_TENANT_CLAIM).# Multi-tenant API keys:
CONTROL_PLANE_API_KEYS=master-key,acme-key:acme,globex-key:globex
# A plain key (no colon) → "default" tenant
# acme-key → "acme" tenant
# globex-key → "globex" tenant
| Data | Isolation |
|---|---|
| Audit chain | Each tenant has its own hash chain. Independent verification. |
| Approvals | Scoped by tenant. Can't read or decide another tenant's requests. |
| Drift baselines | Scoped by tenant. Same metric name can exist per tenant. |
| Prompts & Cost | Each tenant maps to its own prompt management project. |
| Endpoint | Required Role |
|---|---|
POST /approvals/{id}/decide | approver or admin |
POST /drift/baselines, DELETE /drift/baselines/{metric} | admin |
POST /prompts | admin or editor |
POST /users, DELETE /users/{username} | admin |
POST /vkeys, DELETE /vkeys/{id} | admin |
The AI-attack defenses that make WeeBie a real firewall. Where guardrails catch sensitive content, threat protection catches AI-specific attacks and leaks in both prompts and replies — all offline and deterministic, so it works air-gapped.
Off by default; opt in per team. Dashboard → Safety checks → “AI threat
protection”: flip it on, choose detect-only or blocking,
toggle each scanner, pick a block severity, and test text live in the “Try it
out” box. A prompt that trips a detector at/above your block severity is refused
with a 403 when enforcing; otherwise it’s flagged to the violations
feed and audit chain but allowed.
# Enable + enforce (admin)
PUT /api/v1/threat/config {"enabled": true, "enforce": true}
# Scan text on demand
POST /api/v1/threat/scan {"text": "..."}
Keeps your AI working when a provider doesn’t. If your primary provider is down, overloaded, or rate-limiting, WeeBie automatically fails over to a backup — with retries, a circuit breaker, and headers that tell you who served each call.
Give a provider a fallback list in GATEWAY_PROVIDERS:
{"openai": {"base_url": "https://api.openai.com/v1", "api_key": "sk-…",
"models": ["gpt-"], "fallback": ["azure", "together"]},
"azure": {"base_url": "https://your.openai.azure.com", "api_key": "…"},
"together":{"base_url": "https://api.together.xyz/v1", "api_key": "…"}}
A request for a gpt- model tries OpenAI first; on a connection error,
timeout, 429, or 5xx it retries the next provider (same model
name). Tune with GATEWAY_FAILOVER, GATEWAY_RETRIES,
GATEWAY_RETRY_BACKOFF_MS, and the circuit-breaker knobs
(GATEWAY_CB_FAIL_THRESHOLD, GATEWAY_CB_COOLDOWN_S).
X-WeeBie-Provider (who served it) and, on failover, X-WeeBie-Failover.GET /api/v1/gateway/providers (admin) shows each provider’s circuit state (closed / open / half-open) and recent failures.Lifecycle controls on access keys, and SCIM 2.0 so your identity provider manages who has a WeeBie account — the onboarding/offboarding hygiene enterprise IT expects.
PUT /api/v1/vkeys/{id}/expiry.POST /api/v1/vkeys/{id}/rotate issues a new secret and invalidates the old one immediately (same id, label, budget, expiry).GET /api/v1/vkeys/expiring?within_days=7 lists keys about to lapse.
Point your IdP (Okta, Entra ID, OneLogin) at WeeBie’s SCIM endpoint and it
creates, disables, and deletes accounts automatically as people join and leave. Set
SCIM_TOKEN in .env (SCIM is 404 until you do),
give your IdP the base URL https://<host>/scim/v2 and that bearer
token. Provisioned users land in SCIM_DEFAULT_TENANT with
SCIM_DEFAULT_ROLE and sign in through your SSO. Every action is audited.
SCIM provisions the account; sign-in uses WeeBie’s OIDC support. Corporate SAML IdPs (ADFS, Okta/Entra, Ping, Shibboleth) are supported by brokering through the bundled Keycloak — no native SAML stack is added to the air-gapped control plane.
Get WeeBie’s security events — the tamper-evident audit log and guardrail violations — into Splunk, Datadog, Elastic, or any HTTP collector. Both paths are off by default.
SIEM_ENABLED=true
SIEM_SINK=splunk # webhook | splunk | datadog
SIEM_ENDPOINT=https://splunk.corp:8088/services/collector/event
SIEM_TOKEN=<HEC token> # bearer / HEC token / DD-API-KEY
SIEM_FORMAT=json # json | ndjson | cef (webhook sink)
SIEM_SOURCES=audit,guardrail
Because WeeBie denies outbound traffic by default, allowlist your collector’s
host. Confirm end-to-end with POST /api/v1/siem/test (sends one synthetic
event). Streaming is best-effort — if your SIEM is down, WeeBie logs it and never
delays an AI request.
GET /api/v1/siem/export?since=<ISO>&until=<ISO>&sources=audit,guardrail&format=cef
GATEWAY_LOG_CONTENT and SIEM_INCLUDE_CONTENT — metadata-only
is the safe default. Gated by the siem.manage permission.
The privacy/legal controls: keep data only as long as you should, honor a “delete my data” request, and keep traffic in-region. All off by default.
Set how many days to keep AI spend records, guardrail violations, and cached responses per team; anything older is deleted when the purge runs.
PUT /api/v1/governance/retention {"cost_days":90,"violation_days":365,"cache_days":7}
# schedule purges: scripts/governance-purge.sh --install → POST /api/v1/governance/purge
The tamper-evident audit log is never auto-deleted — it’s your compliance record.
POST /api/v1/governance/erase {"subject":"<who>"}
Deletes that subject’s operational records (spend rows, violations). Their audit entries are retained (the immutable record of what happened), the erasure itself is logged, and the chain still verifies afterward.
Tag each provider with a region and set DATA_RESIDENCY_REGION=eu.
The gateway then only routes to in-region providers — if nothing in-region can serve a
model, the request is refused (403) rather than sent out of region.
Gated by governance.manage.
A test suite for your prompts and models. Define a golden set of cases, run it, and get a pass/fail — so you catch “did changing this prompt or model make quality worse?” before it ships.
exact / contains / not_contains / regex — deterministic string checks.json_valid — output is valid JSON (optionally with required keys).no_pii — output leaks no PII/banned terms (reuses the guardrail engine).semantic — output means the same as the expected answer (embedding similarity).judge — an LLM rates the output against a rubric (runs on your local model, stays offline).# Manage suites
GET/PUT/DELETE /api/v1/evals/suites[/{name}]
# Run + gate
POST /api/v1/evals/suites/{name}/run → {"passed": true|false, …}
# CI hook — exits non-zero on regression
bash scripts/eval-gate.sh <suite> [--generate]
Gated by the evals.manage permission, so a QA role can own evals without full admin.
Turns cost tracking into a full FinOps story for finance: who spent what, alerts on spikes, savings tips, and hard spending ceilings per department.
cost_center, then GET /api/v1/finops/showback allocates all spend to those centers with a by-model breakdown and quota state.GET /api/v1/finops/anomalies flags a spike vs. the trailing daily baseline (default: today ≥ 1.5× baseline and ≥ $1).GET /api/v1/finops/recommendations returns advisory savings tips from your ledger + cache stats.PUT /api/v1/finops/quotas sets a monthly USD ceiling per cost center, enforced at the gateway (keys blocked with 402 once hit).Gated by the finops.manage permission, so a finance role can own chargeback and quotas without full admin.
The firewall covers more than chat. Embeddings (the vectors that power search/RAG) and image generation go through the same gateway — so they get the same governance instead of being a blind spot.
# Text → vectors: DLP + threat scanned, failover + residency routed, metered
POST /v1/embeddings
# Prompt → image: scanned/blocked/redacted, routed, metered + audited
POST /v1/images/generations
Both honor your virtual keys, per-key and team budgets, and rate limits, and every call
lands in the audit log as metadata only. Vision inputs in a normal chat request already
pass through /v1/chat/completions unchanged.
Route to Amazon Bedrock and Google Vertex AI through the gateway with their native cloud auth — so enterprises on AWS/GCP use their existing model access, private networking, and contracts, and still get every WeeBie control.
{
"bedrock": {"type": "bedrock", "region": "us-east-1",
"aws_access_key_id": "AKIA…", "aws_secret_access_key": "…",
"models": ["anthropic.claude"]},
"vertex": {"type": "vertex", "project": "my-proj", "location": "us-central1",
"service_account": { …the SA JSON… }, "models": ["gemini"]}
}
Your apps keep calling WeeBie in OpenAI format — WeeBie signs and translates. Bedrock requests are SigV4-signed (v1 targets Anthropic Claude on Bedrock); Vertex uses a minted GCP access token against Vertex’s OpenAI-compatible endpoint. The gateway auto-allowlists the AWS/GCP hosts, and both participate in failover chains and data-residency filtering.
Meet teams in the languages and tools they already use. Thin SDKs ship for five languages — Python, JS/TS, Go, Java, .NET — plus a Terraform provider and framework integrations.
Manage WeeBie as code: weebie_virtual_key, weebie_cost_center_quota, weebie_custom_role.
resource "weebie_custom_role" "finance" { name = "finance" permissions = ["finops.manage"] }
resource "weebie_cost_center_quota" "platform" { cost_center = "platform" monthly_quota_usd = 500 }
resource "weebie_virtual_key" "search" { label = "search-svc" cost_center = "platform" monthly_budget_usd = 100 }
Go (stdlib-only), Java (Maven com.weebie:weebie, Java 11+, no runtime
deps), and .NET (Weebie, net8.0) share the same thin-SDK shape
as Python/JS: Chat / Embeddings / RecordUsage, the
normalized gateway URL, and the feature header.
# Route a framework through WeeBie (Python)
llm = wb.langchain_chat(feature="rag-answerer", model="gpt-4o") # LangChain
Settings.llm = wb.llamaindex_llm(feature="docs-index", model="gpt-4o") # LlamaIndex
Protection against losing the box WeeBie runs on. Three layers, and you keep control of the storage and hardware — WeeBie ships the tooling and points it at your bucket and your recovery node.
pg_dump of the control-plane and Langfuse databases plus cluster roles and a paired secrets snapshot, with retention (default 14 days). On out of the box.# nightly local backups already run (installed cron)
scripts/backup-postgres.sh
# turn on off-box shipping (.env): BACKUP_REMOTE + BACKUP_ENCRYPTION_PASSPHRASE (escrow it!)
# restore onto a fresh box:
scripts/dr-restore.sh --remote <artifact> --from BACKUP_REMOTE --yes
# prove it works right now, free, on one box (non-destructive):
bash scripts/dr-drill.sh
Update an existing install safely with scripts/update.sh — it takes a restore point first and rolls back automatically if the new version isn’t healthy.
WeeBie exposes two APIs: the OpenAI-compatible gateway and the control plane management API.
| API | Base Path | Auth | Purpose |
|---|---|---|---|
| Gateway API | /v1/* | X-API-Key or Authorization: Bearer | OpenAI-compatible — chat completions, models, embeddings |
| Control Plane API | /api/v1/* | X-API-Key or Authorization: Bearer | Management — guardrails, policy, audit, cost, drift, approvals, users |
# API key (service / machine auth):
curl -H "X-API-Key: *** https://your-domain/api/v1/audit/verify
# JWT (human auth — obtained via login):
curl -H "Authorization: Bearer ***" https://your-domain/api/v1/auth/me
When the control plane is running, FastAPI's interactive docs are available at:
https://your-domain/docs — Swagger UIhttps://your-domain/openapi.json — OpenAPI spec| Category | Endpoints |
|---|---|
| Gateway | GET /v1/models, POST /v1/chat/completions |
| Auth | POST /api/v1/auth/login, GET /api/v1/auth/me |
| Users | GET/POST /api/v1/users, DELETE /api/v1/users/{username} |
| Virtual Keys | GET/POST /api/v1/vkeys, DELETE /api/v1/vkeys/{id} |
| Guardrails | POST /api/v1/guardrails/validate, GET/POST /api/v1/guardrails/config |
| Policy | GET/POST /api/v1/policy |
| Approvals | POST /api/v1/approvals/submit, GET /api/v1/approvals, POST /api/v1/approvals/{id}/decide |
| Audit | GET /api/v1/audit/verify, GET /api/v1/audit/export |
| Cost | POST /api/v1/cost/record, GET /api/v1/cost/ledger, GET /api/v1/cost/pricing |
| Drift | POST /api/v1/drift/baselines, POST /api/v1/drift/evaluate, POST /api/v1/drift/psi |
| Observability | GET /api/v1/observe/dashboard, GET /api/v1/observe/metrics |
| MCP | GET /api/v1/mcp/tools, POST /api/v1/mcp/tools/call |
| Notifications | GET /api/v1/notify/status, POST /api/v1/notify/test |
The OpenAI-compatible gateway at /v1. Any app that speaks
the OpenAI API can use it by changing the base URL.
GET /v1/models
# Response:
{
"object": "list",
"data": [
{"id": "gpt-4o", "object": "model", "created": 1782780896, "owned_by": "openai"},
{"id": "llama3.2:1b", "object": "model", "created": 1782780896, "owned_by": "library"}
]
}
POST /v1/chat/completions
# Request:
{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Say hello"}],
"max_tokens": 10,
"stream": false
}
# Response:
{
"id": "chatcmpl-324",
"object": "chat.completion",
"model": "gpt-4o",
"choices": [{
"index": 0,
"message": {"role": "assistant", "content": "Hello!"},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": 10, "completion_tokens": 3, "total_tokens": 13}
}
POST /v1/chat/completions
{"model": "gpt-4o", "messages": [...], "stream": true}
# Response (SSE format):
data: {"id":"chatcmpl-1","choices":[{"delta":{"role":"assistant","content":"Hi"}}]}
data: {"id":"chatcmpl-1","choices":[{"delta":{"content":"."}}]}
data: {"id":"chatcmpl-1","choices":[{"finish_reason":"stop"}]}
# The stream ends with a [DONE] marker.
Use either a service key or a virtual key:
# Service key (full access, bypasses RBAC)
-H "X-API-Key: 17b908954be8..."
# Virtual key (per-team, budget-limited)
-H "X-API-Key: uamcs-lGqI_R0q..."
# OIDC JWT (user auth)
-H "Authorization: Bearer eyJhbG..."
The management API at /api/v1 for guardrails, policy,
audit, cost, drift, approvals, users, and virtual keys.
# Validate text
POST /api/v1/guardrails/validate
{"text": "email me at test@example.com", "redact": true}
# Get / update config
GET /api/v1/guardrails/config
POST /api/v1/guardrails/config
{"block_pii": true, "banned_terms": ["confidential"], "max_length": 4096}
# Violations feed
GET /api/v1/guardrails/violations
# Submit action for approval
POST /api/v1/approvals/submit
{"tool": "send_email", "arguments": {"to": "ceo@corp.com"}, "actor": "agent:bot"}
# List approvals (filter by status)
GET /api/v1/approvals?status=pending&limit=10
# Decide
POST /api/v1/approvals/{id}/decide
{"decision": "approve", "decided_by": "admin", "note": "OK"}
# Verify chain integrity
GET /api/v1/audit/verify
# → {"intact": true, "first_broken_seq": null}
# Export all records
GET /api/v1/audit/export
# Query records
GET /api/v1/audit/records?limit=20
# Append custom record
POST /api/v1/audit/append
{"action": "manual_review", "actor": "admin", "timestamp": "2026-07-06T12:00:00Z"}
# Record cost event
POST /api/v1/cost/record
{"model": "gpt-4o", "input_tokens": 500, "output_tokens": 500,
"endpoint": "/v1/chat/completions", "actor": "user:alice"}
# Query ledger
GET /api/v1/cost/ledger?days=7
# Pricing table
GET /api/v1/cost/pricing
# Create baseline
POST /api/v1/drift/baselines
{"metric": "response_latency", "values": [0.2, 0.22, ...], "bins": 10}
# Evaluate
POST /api/v1/drift/evaluate
{"metric": "response_latency", "current": [0.8, 0.9, ...]}
# Stateless PSI
POST /api/v1/drift/psi
{"baseline": [0.2, ...], "current": [0.8, ...]}
# List users
GET /api/v1/users
# Create user
POST /api/v1/users
{"username": "alice", "password": "strong-pass", "role": "viewer"}
# Delete user
DELETE /api/v1/users/{username}
# Change password
POST /api/v1/users/{username}/password
{"password": "new-pass"}
# Change role
POST /api/v1/users/{username}/role
{"role": "approver"}
# Create key
POST /api/v1/vkeys
{"label": "Engineering Team", "budget_monthly": 500.00}
# List keys
GET /api/v1/vkeys
# Revoke key
DELETE /api/v1/vkeys/{id}
# Check notification status
GET /api/v1/notify/status
# Send test notification
POST /api/v1/notify/test
Keep WeeBie healthy: backups, updates, and routine maintenance.
# Nightly database backups are automated. Install the daily cron once:
bash scripts/backup-postgres.sh --install # both DBs + globals + secrets snapshot, 14-day retention
# Ship each backup OFF-BOX (encrypted) to your own storage — set in .env:
# BACKUP_REMOTE=<rclone-remote:bucket>
# BACKUP_ENCRYPTION_PASSPHRASE=<secret — escrow it off the box>
# Empty BACKUP_REMOTE = local-only; off-box upload is refused unless encrypted.
# Check disk space and container health:
df -h /
docker compose ps
# Update WeeBie (install the latest package from WeeBie)
cd /opt/your-install-dir
tar xzf weebie-update-package.tar.gz
docker compose build
docker compose up -d
# Verify audit chain still intact:
curl -H "X-API-Key: *** https://your-domain/api/v1/audit/verify
# Run the test suite:
docker exec the-control-plane-container python3 -m pytest /app/tests/ -v
bash scripts/dr-drill.sh (one box, no external infra) or a full restore to a spare hostsudo apt update && sudo apt upgrade# 1. Provision a new host; point DNS at it
# 2. Clone the repo, then restore secrets from the backup set (or your vault):
cp <backup>/env.snapshot .env
cp <backup>/s3.json.snapshot config/seaweedfs/s3.json
# 3. Restore + verify in one step (pull off-box, decrypt, restore, check):
BACKUP_ENCRYPTION_PASSPHRASE=<secret> \
bash scripts/dr-restore.sh --remote <stamp>.tar.gpg --from BACKUP_REMOTE --yes
# 4. Bring up the full stack:
docker compose --profile edge --profile llm up -d
# 5. Verify the audit chain survived the restore:
curl -H "Authorization: Bearer $ADMIN_TOKEN" https://your-domain/api/v1/audit/verify
# → {"intact": true, "first_broken_seq": null}
See the full runbook — one-time off-box setup, the quarterly drill, and secrets
escrow — in docs/dr-restore.md.
BACKUP_REMOTE + BACKUP_ENCRYPTION_PASSPHRASE, backups
live only on the host, and a destroyed disk loses everything since your last
off-box copy. Configure it, then prove the whole path end-to-end with
bash scripts/dr-drill.sh.
Common issues and how to fix them. Written so a non-expert can act safely.
docker compose ps # what's running?
curl -s https://your-domain/health # core alive?
docker compose logs --tail=100 # recent errors?
ping <host-ip> — no reply → host/provider problem (reboot from hosting panel)docker compose --profile edge up -d edgedocker compose logs edge | grep -i acmedocker logs --tail=50
# Known signatures:
# "Refusing to start in production with default secrets"
# → Someone left a placeholder in .env. Fix the named variable.
# Prisma P3005 (prompt manager):
# → It needs its OWN database. Set PROMPT_DB=promptmgr.
# "unable to unzip the plugin archives" (dashboard engine):
# → Don't mount the whole ./config/dashboards over /etc/dashboards.
# Use the shipped compose file as-is.
df -h / # >90% = this is your incident
docker system prune -f # old images/layers — safe
du -sh backups/* | tail # prune old backups beyond retention
CONTROL_PLANE_API_KEYS in .env, then docker compose up -d control-plane dashboard.A ~1 second 502 right after a dashboard restart is normal — retry before digging in.
Production hardening checklist for deploying WeeBie in a security-conscious environment.
| Task | Status |
|---|---|
Replace every default secret in .env | Required |
Set UAMCS_ENV=production | Required |
Set CORS_ALLOW_ORIGINS to your dashboard origin only | Required |
Keep login enabled (AUTH_REQUIRE_LOGIN=true) | Default |
| Change the seeded admin password after first login | Required |
| Put TLS + reverse proxy (TLS Edge) in front | Default |
| Set a webhook authentication token if the alert webhook is reachable | Recommended |
Turn on OIDC for human users (AUTH_KEYCLOAK_ISSUER) | Recommended |
| Pin image tags to digests for reproducibility | Recommended |
| Rotate API keys; scope each to its tenant | Recommended |
| Back up database + object storage (audit chain is the compliance record) | Required |
For air-gap: UAMCS_AIRGAPPED=true + host firewall denying egress | If applicable |
Periodically call GET /api/v1/audit/verify and alert if not intact | Recommended |
| Asset | Threats | Controls |
|---|---|---|
| Unified API | Unauthorized access | API-key or OIDC auth on every route; RBAC on mutations |
| Tenant data | Cross-tenant access | Per-tenant isolation; per-tenant audit chains |
| Audit log | Silent tampering | SHA-256 hash chain + off-DB mirror; /audit/verify |
| Agent tools | Dangerous actions | Policy + approval queue + audit (MCP gateway) |
| AI output | PII leakage | Guardrails (PII/length/banned-term) |
| Whole system | Data exfiltration | Air-gap egress lock enforced in code |
| Secrets | Leakage to browser | Dashboard keeps API key server-side; never sent to client |
bash scripts/generate-sbom.sh # SBOM + bandit + pip-audit
# or individually:
bandit -r control-plane/app
pip-audit
python scripts/generate_sbom.py