Beautiful command-line interface for QWED verification.
Installation
The qwed CLI is automatically available after installation.
Commands
qwed init - Onboarding and bootstrap
Production-grade onboarding wizard that sets up verification engines, configures your LLM provider, and bootstraps a local API key — all in a single command. Run this once after installing QWED.
The wizard runs three steps:
- Engine readiness — checks that core verification engines (SymPy, Z3, AST, SQLGlot) are installed, then runs deterministic smoke tests to confirm they work correctly
- LLM provider setup — select a provider, enter credentials with masked input, validate the key format, and test the connection with retry support
- API key bootstrap — starts a local QWED server, creates an organization, and generates a one-time API key you can use immediately
Supported providers:
| Provider | Slug | Default model | Key env variable |
|---|
| NVIDIA NIM | nvidia | API key | Any key format |
| OpenAI | openai | API key | sk-... or sk-proj-... |
| Anthropic | anthropic | API key | sk-ant-... |
| Google Gemini | gemini | API key | Google API key |
| Custom (OpenAI-compatible) | custom | Endpoint + key | Any bearer token |
Example session:
$ qwed init
[QWED] Initializing verification engines...
[ok] SymPy math engine ready
[ok] Z3 logic engine ready
[ok] AST code engine ready
[ok] SQLGlot sql engine ready
Running verification suite...
[ok] 2+2=5 -> BLOCKED
[ok] x>5 AND x<3 -> UNSAT
[ok] SELECT * FROM users ... -> BLOCKED
[ok] os.system(...) -> BLOCKED
All engines verified. QWED is operational.
-----------------------------------------
Step 1/3: LLM Provider Setup
-----------------------------------------
QWED uses an LLM for natural language translation.
The LLM is treated as an untrusted translator.
All outputs are verified deterministically.
Select provider:
1. NVIDIA NIM
2. OpenAI
3. Anthropic Claude
4. Google Gemini
5. Custom Provider (any OpenAI-compatible API)
Provider: 2
-----------------------------------------
Step 2/3: API Key
-----------------------------------------
OpenAI API key: ****
Testing connection...
[ok] Provider connected
[ok] Model responding
[ok] Credentials stored (.env, mode 0600)
-----------------------------------------
Step 3/3: Generate QWED API Key
-----------------------------------------
Starting local server...
[ok] Local server initialized
[ok] Organization created
Your API key: qwed_xxxxxxxxxxxxxxxx
Warning: Save this key. It is shown only once.
-----------------------------------------
QWED is ready.
Verify an output:
curl -X POST http://localhost:8000/verify/math \
-H "x-api-key: qwed_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"expression": "2+2=4"}'
Documentation: https://docs.qwedai.com
-----------------------------------------
Non-interactive mode (CI/CD)
Use --non-interactive to run qwed init without prompts. This is useful in CI pipelines, Docker builds, or automated provisioning scripts.
qwed init \
--non-interactive \
--provider openai \
--api-key "$OPENAI_API_KEY" \
--model gpt-4o-mini \
--organization-name my-team \
--skip-tests
All flags:
| Flag | Description | Default |
|---|
--provider | Provider to configure (nvidia, openai, anthropic, gemini, custom) | Interactive prompt (or nvidia in non-interactive mode) |
--api-key | Provider API key (placeholder values are ignored) | Read from environment |
--base-url | Base URL for custom/OpenAI-compatible providers | Provider default |
--model | Default model for the provider | Provider default |
--organization-name | Organization name for API key bootstrap | Interactive prompt (or auto-generated) |
--server-url | Local QWED server URL | http://localhost:8000 |
--non-interactive | Run without prompts (CI-friendly) | false |
--skip-tests | Skip the engine smoke tests | false |
API keys are never logged or displayed in full. The .env file is written atomically with owner-only permissions (0600 on Unix) and symlink protection. A QWED_JWT_SECRET_KEY is generated automatically for local server authentication.
Local server runtime directory:
During Step 3, qwed init starts a local API server and needs a writable location for the SQLite bootstrap database (qwed.db). The CLI resolves the runtime directory as follows:
- Current working directory — used if it is writable
~/qwed-demo/ — created and used as a fallback when the current directory is read-only (e.g., inside a container, a mounted volume, or a system-managed path)
The server process starts with its working directory set to this runtime directory, and DATABASE_URL is explicitly set to sqlite:///<runtime_dir>/qwed.db. This ensures bootstrap writes never target a read-only path.
If you previously encountered sqlite3.OperationalError: attempt to write a readonly database during qwed init, upgrade to v4.0.0 or later. The fix automatically resolves a writable directory so Step 3 succeeds regardless of where you run the command.
Security guarantees:
- Keys are entered with masked input and never displayed in full
- Keys are never written to logs
.env is written with 0600 permissions (owner-read/write only on Unix)
.gitignore protection is enforced before writing secrets — the command aborts if .env cannot be gitignored
- Atomic file writes prevent partial credential exposure
- Symlink targets are refused to prevent path traversal
.gitignore protection is enforced before writing secrets
Placeholder API key detection: During onboarding, qwed init automatically detects and ignores common placeholder or dummy API key values. If your environment variable or --api-key argument contains a value like your-api-key, changeme, placeholder, xxx, or a short NVIDIA key such as nvapi-xxxx, QWED treats it as empty and prompts you for a real key. This prevents silent failures caused by example values left in .env files or CI templates.
The following patterns are rejected:
- Generic placeholders:
test, dummy, sample, example, placeholder, changeme, null, none
- Wildcard-style values: strings made entirely of
x, *, or . characters (e.g. xxx, ****)
- Template values: strings starting with
your- or replace- that contain key
- Short NVIDIA keys:
nvapi- prefixed values shorter than 20 characters
In non-interactive mode, if every key source (CLI argument, environment variable, and NVIDIA fallback) resolves to a placeholder, the command reports that the key is required and exits — so you get a clear error instead of a cryptic provider failure downstream.
Re-running qwed init: Running the command again merges new values into your existing .env file. Existing variables that you don’t reconfigure are preserved.
qwed doctor - System health check
Run a local health check that reports the status of verification engines, LLM provider connectivity, the QWED server, and the database. Use this after installation or when verification calls fail unexpectedly.
What it checks:
| Check | Description |
|---|
| Required engines | SymPy (math), Z3 (logic), AST (code), SQLGlot (SQL) |
| Optional engines | OpenCV (image verification) |
| Provider | Connectivity to the configured LLM provider |
| Server | Whether the QWED API server is reachable |
| Database | Health of the configured database |
The command exits with code 0 when all required checks pass (status OPERATIONAL) and code 1 when any required check fails (status DEGRADED). Optional engines that are missing do not cause a degraded status.
.env override behavior
The doctor command loads your .env file with override mode enabled. This means values in your .env file take precedence over variables already set in the current shell environment.
For example, if your shell has ACTIVE_PROVIDER=ollama but your .env file contains ACTIVE_PROVIDER=openai_compat, the doctor report reflects the .env value (openai_compat). This ensures the health report matches the configuration your application actually uses at runtime.
Database URL resolution
When checking database health, doctor prefers the DATABASE_URL environment variable (including values loaded from .env) over the application settings default. The resolution order is:
DATABASE_URL from environment / .env — used if present and non-empty
- Application settings — the
DATABASE_URL from your QWED configuration
- Default — falls back to
sqlite:///./qwed.db
This ensures the doctor report checks the database your deployment actually connects to, even when DATABASE_URL is set via environment variables rather than application config.
Example output:
$ qwed doctor
[QWED] System Health Check
Engines:
[ok] SymPy 1.13.3 math engine ready
[ok] Z3 4.13.4 logic engine ready
[ok] AST built-in code engine ready
[ok] SQLGlot 26.30.0 sql engine ready
[x] OpenCV missing image verification
-> pip install qwed[vision]
Provider:
[ok] OpenAI - Connected (gpt-4o-mini)
Server:
[ok] Running on http://localhost:8000
Database:
[ok] src/qwed.db (healthy)
Status: OPERATIONAL (1 optional engine missing)
JSON output (CI/CD)
Use --json for machine-readable output. Useful in CI pipelines or monitoring scripts.
{
"status": "OPERATIONAL",
"optional_missing_count": 1,
"engines": [
{ "name": "SymPy", "ready": true, "detail": "math engine ready", "version": "1.13.3" },
{ "name": "Z3", "ready": true, "detail": "logic engine ready", "version": "4.13.4" }
],
"provider": { "ok": true, "label": "OpenAI", "message": "Connected (gpt-4o-mini)" },
"server": { "running": true, "url": "http://localhost:8000" },
"database": { "healthy": true, "location": "src/qwed.db" }
}
Options:
| Flag | Description | Default |
|---|
--json | Print the full report as JSON instead of the human-readable table | false |
Run qwed doctor --json in CI to gate deployments on system health. A non-zero exit code means at least one required component is degraded.
qwed test - Deterministic verification tests
Run the built-in deterministic test suite across the Math, Logic, SQL, and Code engines. Every test case has a known expected result and does not depend on an LLM, so outcomes are fully reproducible.
Use this command to confirm that verification engines are working correctly after installation, upgrades, or environment changes.
What it tests:
| Engine | Test cases |
|---|
| Math | Valid expression (2+2=4), invalid expression (2+2=5), large computation |
| Logic | Contradictions (x>5 AND x<3), satisfiable constraints, conflicting assignments |
| SQL | Valid SELECT, OR 1=1 injection detection, stacked DROP TABLE detection |
| Code | Safe function, eval(input()) detection, curl | bash detection |
The command exits with code 0 when all tests pass and code 1 when any test fails.
Example output:
$ qwed test
[QWED] Running verification test suite...
Math:
[ok] 2+2=4 -> VALID
[ok] 2+2=5 -> BLOCKED
[ok] 997*997-3*997+2 -> 994010994 (verified)
Logic:
[ok] x>5 AND x<3 -> UNSAT (contradiction)
[ok] x>3 AND x<10 -> SAT {x=4}
[ok] approval=1 AND approval=0 -> UNSAT (contradiction)
SQL:
[ok] Valid SELECT -> SAFE
[ok] OR 1=1 injection -> BLOCKED
[ok] DROP TABLE stacked -> BLOCKED
Code:
[ok] Safe function -> SAFE
[ok] eval(input) -> BLOCKED (CRITICAL)
[ok] curl | bash -> BLOCKED (CRITICAL)
12/12 tests passed. All engines operational.
Verbose mode
Use --verbose to show additional detail per test case, such as computed values and internal status codes.
Math:
[ok] 2+2=4 -> VALID
computed=4
[ok] 2+2=5 -> BLOCKED
computed=4
Options:
| Flag | Description | Default |
|---|
--verbose | Show per-case detail (computed values, status codes) | false |
qwed verify - One-shot verification
Verify a query and exit.
qwed verify "What is 2+2?"
qwed verify "derivative of x^2" --provider openai
qwed verify "Is (p AND q) satisfiable?" --model llama3
Options:
--provider, -p - LLM provider (openai, anthropic, gemini)
--model, -m - Model name (e.g., gpt-4o-mini, llama3)
--base-url - Custom API endpoint (for Ollama: http://localhost:11434/v1)
--api-key - API key (or use QWED_API_KEY env var)
--no-cache - Disable caching
--quiet, -q - Minimal output (for scripts)
--mask-pii - Mask PII (emails, phone numbers, etc.) before sending queries to the LLM
Examples:
# Ollama (auto-detected)
qwed verify "2+2"
# OpenAI
qwed verify "factorial of 5" --provider openai --api-key sk-...
# Custom endpoint
qwed verify "x^2 derivative" --base-url http://localhost:11434/v1 --model mistral
# Quiet mode
qwed verify "2+2" --quiet # Just outputs: ✅ VERIFIED: 4
qwed interactive - Interactive Mode
Start an interactive REPL session.
qwed interactive
qwed interactive --provider openai
qwed interactive --model llama3
Usage:
$ qwed interactive
🔬 QWED Interactive Mode
Type 'exit' or 'quit' to quit
> What is 2+2?
🔬 QWED Verification | Math Engine
📝 LLM Response: 4
✅ VERIFIED → 4
> stats
📊 Cache Statistics
Hits: 0
Misses: 1
Hit Rate: 0.0%
> exit
Special Commands:
stats - Show cache statistics
exit, quit, q - Exit interactive mode
qwed cache - Cache Management
Manage verification result cache.
qwed cache stats
Show cache statistics.
$ qwed cache stats
📊 Cache Statistics
Hits: 156
Misses: 44
Hit Rate: 78.0%
Total Entries: 42/1000
Cache Size: 12.3 KB
qwed cache clear
Clear all cached results.
$ qwed cache clear
Are you sure you want to clear the cache? [y/N]: y
✅ Cache cleared!
qwed pii - PII detection
Test PII detection on arbitrary text. Requires the qwed[pii] extra.
qwed pii "My email is john@example.com"
qwed pii "Card: 4532-1234-5678-9010"
Example output:
Original: My email is john@example.com
Masked: My email is [EMAIL_REDACTED]
Detected: 1 entities
- EMAIL: 1
Install PII support with pip install 'qwed[pii]' and download the spaCy model: python -m spacy download en_core_web_lg.
Environment variables
ACTIVE_PROVIDER
Set by qwed init. Tells the CLI which provider to use when no --provider or --base-url flag is given.
# Set automatically by qwed init, or manually:
export ACTIVE_PROVIDER=openai
Valid values: openai, anthropic, gemini, openai_compat.
Provider-specific variables
These are written to .env by qwed init and loaded automatically via python-dotenv:
| Variable | Provider | Description |
|---|
OPENAI_API_KEY | OpenAI | Your OpenAI API key |
OPENAI_MODEL | OpenAI | Model name (default: gpt-4o-mini) |
ANTHROPIC_API_KEY | Anthropic | Your Anthropic API key |
ANTHROPIC_MODEL | Anthropic | Model name (default: claude-sonnet-4-20250514) |
GOOGLE_API_KEY | Google Gemini | Your Google API key |
GEMINI_MODEL | Google Gemini | Model name (default: gemini-1.5-pro) |
CUSTOM_BASE_URL | NVIDIA NIM / Custom | Endpoint URL (required for custom; default https://integrate.api.nvidia.com/v1 for NVIDIA) |
CUSTOM_API_KEY | NVIDIA NIM / Custom | API key for the endpoint |
CUSTOM_MODEL | NVIDIA NIM / Custom | Model name (default: nvidia/nemotron-3-super-120b-a12b for NVIDIA, gpt-4o-mini for custom) |
QWED_JWT_SECRET_KEY | All | JWT secret for local server authentication (auto-generated by qwed init) |
The recommended way to set these is via qwed init, which writes them to a .env file automatically. You can also export them manually.
DATABASE_URL
Override the default database connection used by QWED. When set, qwed doctor uses this value for its health check instead of the application settings default.
export DATABASE_URL="postgresql://user:pass@db.example.com:5432/qwed"
Supported schemes include sqlite, postgresql, mysql, and mariadb. For SQLite, use the sqlite:/// prefix (e.g., sqlite:///./qwed.db for a relative path or sqlite:////absolute/path/qwed.db for an absolute path).
QWED_API_KEY
Fallback API key when a provider-specific key is not set.
export QWED_API_KEY="sk-proj-..."
qwed verify "2+2"
QWED_QUIET
Disable colorful branding output.
export QWED_QUIET=1
qwed verify "2+2" # Minimal output
Configuration
Provider priority
When you run qwed verify without explicit flags, the CLI resolves the provider in this order:
- Command-line flags —
--provider or --base-url take highest precedence
ACTIVE_PROVIDER env var — set by qwed init or manually in .env
- Ollama default — falls back to
http://localhost:11434/v1 with model llama3
If you have run qwed init, the ACTIVE_PROVIDER value in your .env determines which provider and credentials are used automatically.
Default models
| Provider | Default Model |
|---|
| NVIDIA NIM | nvidia/nemotron-3-super-120b-a12b |
| OpenAI | gpt-4o-mini |
| Anthropic | claude-sonnet-4-20250514 |
| Google Gemini | gemini-1.5-pro |
| Custom (OpenAI-compatible) | gpt-4o-mini |
Colorful Output (Default)
🔬 QWED Verification | Math Engine
📝 LLM Response: 4
✅ VERIFIED → 4
────────────────────────────────────────────────────────
✨ Verified by QWED | Model Agnostic AI Verification
💚 If QWED saved you time, give us a ⭐ on GitHub!
👉 https://github.com/QWED-AI/qwed-verification
────────────────────────────────────────────────────────
Quiet Output (--quiet)
Error Output
❌ Error: Ollama not running. Either:
1. Start Ollama: ollama serve
2. Or specify provider explicitly
qwed provider - Custom provider management
Manage custom LLM providers defined in ~/.qwed/providers.yaml. See Custom providers for the full guide.
qwed provider import <url>
Import a community provider definition from a URL. The YAML file is downloaded, validated, and saved locally.
qwed provider import https://raw.githubusercontent.com/my-org/qwed-providers/main/groq.yaml
Example output:
ℹ️ Downloading provider from https://raw.githubusercontent.com/my-org/qwed-providers/main/groq.yaml...
✅ Successfully imported provider 'groq'!
You can now run 'qwed init' and select it from the interactive menu.
After importing, the new provider appears as a selectable option when you run qwed init.
Only http and https URLs are accepted. The imported YAML must contain base_url and api_key_env fields. Downloads time out after 10 seconds.
Use Cases
1. Quick Verification
qwed verify "Is 17 a prime number?"
2. Scripting
#!/bin/bash
export QWED_QUIET=1
export QWED_API_KEY="sk-..."
result=$(qwed verify "2+2" --provider openai)
if [[ $result == *"VERIFIED"* ]]; then
echo "Math checks out!"
fi
3. Local Development
# Start Ollama
ollama serve
# Verify without API costs
qwed interactive
> What is the derivative of x^3?
✅ VERIFIED → 3*x**2
# First run (cache miss)
time qwed verify "complex calculation" # ~2 seconds
# Second run (cache hit)
time qwed verify "complex calculation" # ~0.1 seconds!
Troubleshooting
”Ollama not running"
# Check Ollama status
curl http://localhost:11434/v1/models
# Start Ollama
ollama serve
"API key required"
# Set env var
export QWED_API_KEY="sk-..."
# Or pass directly
qwed verify "query" --api-key sk-...
"Module not found”
# Install missing LLM clients
pip install openai anthropic google-generativeai
# Install verification engines
pip install sympy z3-solver
Advanced Features
Caching Behavior
- Default: Enabled (24h TTL)
- Disable:
--no-cache flag
- Clear:
qwed cache clear
- Stats:
qwed cache stats
Multiple Providers
# Compare results across providers
qwed verify "2+2" --provider openai
qwed verify "2+2" --base-url http://localhost:11434/v1
qwed verify "2+2" --provider anthropic