Installation
qwed CLI is automatically available after installation.
Commands
qwed init - onboarding and bootstrap
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.
- 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 — asks for the organization name and owner, starts a local QWED server, verifies the server’s identity, creates an organization, and generates a one-time API key you can use immediately
Example session:
qwed init run prints the full v2 key (qwed_live_ + 36 characters) once, at that moment.
Organization owner
qwed init signs up the organization it creates with an owner email and password. Use them to sign in to the organization later, for example to read its records in qwed-dashboard.
- Email. Pass
--owner-email, or setQWED_OWNER_EMAIL.qwed initreadsQWED_OWNER_EMAILonly when--owner-emailis not given. An explicit empty or blank--owner-emailis refused (or asked again interactively), never replaced by the environment variable. In interactive mode without either,qwed initasks for the email right after the organization name. - Password.
qwed initprompts for the password with hidden input and asks you to confirm it. There is no password flag, so the password stays out of your shell history.qwed initnever prints the password or saves it to.env.
qwed init checks both values before it starts the server. The server runs the full email validation.
If the email is already registered, signup fails with
Email already registered. qwed init then tells you how to continue: sign in with that owner (for example to qwed-dashboard) and create a key there, or re-run with another email.
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 reads the owner password from QWED_OWNER_PASSWORD. Set it from your CI secret store before you run the command:
- Owner email without a password. If you pass an owner email (flag or
QWED_OWNER_EMAIL) andQWED_OWNER_PASSWORDis unset or empty,qwed initprints--owner-email with --non-interactive needs QWED_OWNER_PASSWORD set., exits with status1, and stops before the server starts. - Password isolation.
qwed initremovesQWED_OWNER_PASSWORDfrom the environment of the local server it starts. The server never sees it outside the signup request. - No owner email.
qwed initcreates the organization with a generated owner whose credentials are never shown or saved, and prints a warning that nobody can sign in to the organization. Its records cannot be read in qwed-dashboard.
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. qwed init auto-generates three server secrets on first run. QWED_JWT_SECRET_KEY signs JWTs. QWED_API_KEY_LOOKUP_SECRET derives the HMAC-SHA256 digests the server uses to look up API keys. QWED_AUDIT_SECRET_KEY signs the audit hash chain, and the server refuses to start without it. All three are passed into the local server it starts. If the project-root .env already sets QWED_AUDIT_SECRET_KEY, qwed init reuses that value. The fail-closed import check at server boot no longer trips on a fresh install.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)
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.qwed init proves that the server answering on --server-url holds this project’s secrets. A healthy GET /health only shows that something answers on the port. A foreign process, or a stale QWED server started with older secret values, would otherwise receive the bootstrap request and issue a key that the intended server cannot resolve after a restart.
The handshake runs on both paths: when qwed init reuses an already-running server, and when it spawns a fresh one.
qwed initgenerates a fresh random nonce for each run (24 random bytes, URL-safe Base64).- It calls
GET /health/identitywith that nonce. - The server returns HMAC-SHA256 proofs over the nonce under
QWED_JWT_SECRET_KEY,QWED_API_KEY_LOOKUP_SECRET, andQWED_AUDIT_SECRET_KEY(audit_hmac). A server on a different audit key would write audit rows this project’s server can’t verify after a restart. qwed initcomputes the expected proofs from its local secrets and compares them in constant time.
qwed init prints [x] Server identity check failed: <reason>, exits with status 1, and does not bootstrap a key when:
Security guarantees:
- Keys are entered with masked input and never displayed in full
- Keys are never written to logs
.envis written with0600permissions (owner-read/write only on Unix).gitignoreprotection is enforced before writing secrets — the command aborts if.envcannot be gitignored- Atomic file writes prevent partial credential exposure
- Symlink targets are refused to prevent path traversal
.gitignoreprotection is enforced before writing secrets
qwed init automatically detects and ignores common placeholder or dummy API key values. If your environment variable or --api-key argument contains a placeholder value, QWED treats it as empty and prompts you for a real key. Recognized placeholders include your-api-key, changeme, placeholder, xxx, and short NVIDIA keys such as nvapi-xxxx. 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-orreplace-that containkey - Short NVIDIA keys:
nvapi-prefixed values shorter than 20 characters
qwed init: Running the command again merges new values into your existing .env file. Existing variables that you don’t reconfigure are preserved. All three server secrets (QWED_JWT_SECRET_KEY, QWED_API_KEY_LOOKUP_SECRET, and QWED_AUDIT_SECRET_KEY) are retained across re-runs and never rotated automatically. Rotating the lookup secret invalidates every previously issued API key’s lookup digest. Rotating the audit key invalidates the signature on every audit row already written. Projects onboarded before the audit key was required have no QWED_AUDIT_SECRET_KEY in .env. Re-run qwed init to add one; your existing secrets are kept. If your .env already sets QWED_API_KEY_LOOKUP_SECRET equal to QWED_JWT_SECRET_KEY, qwed init refuses to continue: reusing the JWT secret is a value the server will not boot with. Remove the offending line (a fresh, distinct value is generated) or set a distinct value manually. See API key storage and migration for why the lookup secret must stay stable.
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.
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_URLfrom environment /.env— used if present and non-empty- Application settings — the
DATABASE_URLfrom your QWED configuration - Default — falls back to
sqlite:///./qwed.db
DATABASE_URL is set via environment variables rather than application config.
Example output:
JSON output (CI/CD)
Use--json for machine-readable output. Useful in CI pipelines or monitoring scripts.
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.
The command exits with code
0 when all tests pass and code 1 when any test fails.
Example output:
VERIFIED never appears alone. VERIFIED means the engine decided the claim, not that the claim is safe to use. A claim proven false, such as 2+2=5, is VERIFIED (false) | DENY. A test case whose self-check fails prints FAILED instead of a verdict, and an engine that raises prints ERROR.
Verbose mode
Use--verbose to show additional detail per test case, such as computed values and internal status codes.
qwed verify - one-shot verification
Verify a query and exit.
--provider, -p- LLM provider (openai,anthropic,gemini)--model, -m- Model name (e.g.,gpt-4o-mini,llama3). Without it, the CLI reads the selected provider’s model variable (see Provider-specific variables). With an explicit--base-url, it reads no model variable, so pass--model--base-url- Custom API endpoint (for Ollama:http://localhost:11434/v1)--api-key- API key (or useQWED_API_KEYenv var). The providerqwed initsaved gets a key only from--api-keyon the command line or from its own key variable, never fromQWED_API_KEY--no-cache- Disable caching--quiet, -q- Minimal output (for scripts)--mask-pii- Mask PII (emails, phone numbers, etc.) before sending queries to the LLM
--model nor the provider’s model variable is set, qwed verify stops with an error that names the variable to set. With an explicit --base-url, qwed verify reads no model variable, not even CUSTOM_MODEL, and the error asks for --model.
Examples:
qwed interactive - interactive mode
Start an interactive REPL session.
--provider, qwed interactive runs the provider qwed init saved in ACTIVE_PROVIDER, with its endpoint and key, as qwed verify does. It takes the model from --model, else from that provider’s model variable, and stops with an error naming the variable when neither is set.
Usage:
stats- Show cache statisticsexit,quit,q- Exit interactive mode
qwed cache - cache management
Manage verification result cache.
qwed cache stats
Show cache statistics.
qwed cache clear
Clear all cached results.
qwed pii - PII detection
Test PII detection on arbitrary text. Requires the qwed[pii] extra.
Install PII support with
pip install 'qwed[pii]' and download the spaCy model: python -m spacy download en_core_web_lg.qwed context - Verification Context utilities
New in v7.1.0
validate and from-diagnostic exit with code 1 on any failure. resolve exits with code 1 when it can’t read the file or the attestation check fails, but exits with code 0 when the commitment doesn’t resolve. In CI, gate on the resolved field, not only the exit code.
validate and resolve check a document’s attestation by default: it must verify with the issuing server’s keys and sign this document. Pass the keys with one of these options:
Pass
--server or --jwks-file, not both. The attestation errors are:
qwed context validate
Validate a Verification Context document file against the JSON Schema of its spec_version (v1.0 or v1.1), including the verdict/proof_ref invariants, after the attestation check.
{"valid": false, "error": "..."} and exits with code 1. Error values are the attestation errors above, invalid_document_file (file could not be read or parsed as JSON) and validation_failed (schema or invariant violation).
qwed context resolve
Resolve the proof_ref evidence commitment of a document file. The command re-derives the SHA-256 commitment over the canonical bound payload and compares it to the stored value, after the attestation check.
resolved is true only for a schema-valid VERIFIED document whose attestation verifies and whose stored proof_ref matches the re-derived commitment. An attestation failure prints {"resolved": false, "error": "..."} and exits with code 1. Any other outcome prints {"resolved": false} and exits with code 0, so check the resolved field: a proof_ref that doesn’t resolve confers no authority.
qwed context from-diagnostic
Create a Verification Context document from a DiagnosticResult JSON file and print it. The command runs locally and has no signing key, so it prints an unsigned v1.0 document. Validate it with --no-require-attestation. For a signed document, use the server’s POST /verification-context/from-diagnostic.
A malformed diagnostic file produces a
BLOCKED document rather than a crash. A VERIFIED diagnostic without a valid attestation token fails closed to BLOCKED (fail-closed).
Environment variables
ACTIVE_PROVIDER
Set by qwed init. Tells the CLI which provider to use when no --provider or --base-url flag is given.
ollama, openai-compatible (or openai_compat), openai, openai_direct (run as openai), anthropic, and gemini. The CLI reads the value as the server does: in any case, with -, _, or a space. When ACTIVE_PROVIDER is unset, the CLI runs Ollama.
A provider only the server runs, such as azure_openai or auto, stops qwed verify and qwed interactive with an error naming ACTIVE_PROVIDER. So does anthropic with ANTHROPIC_ENDPOINT set, because the CLI calls the Anthropic API directly.
Provider-specific variables
These are written to.env by qwed init and loaded automatically via python-dotenv:
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.
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
API key that qwed verify --api-key reads when the flag is not given. It is used with an explicit --provider or --base-url. It is never sent to the provider qwed init saved in ACTIVE_PROVIDER, because it may be your QWED server’s key: set that provider’s own key variable (such as OPENAI_API_KEY) instead.
QWED_QUIET
Disable colorful branding output.
Configuration
Provider priority
When you runqwed verify without explicit flags, the CLI resolves the provider in this order:
- Command-line flags —
--provideror--base-urltake highest precedence ACTIVE_PROVIDERenv var — set byqwed initor manually in.env- Ollama: when
ACTIVE_PROVIDERis unset, the CLI runs Ollama atOLLAMA_BASE_URL(defaulthttp://localhost:11434/v1)
qwed init, the ACTIVE_PROVIDER value in your .env determines which provider and credentials are used automatically.
Models
QWED names no default model. Each provider runs the model you configure, from--model or the provider’s model variable (OPENAI_MODEL, ANTHROPIC_MODEL, GEMINI_MODEL, OLLAMA_MODEL, or CUSTOM_MODEL). The value is sent to the provider unchanged, so any model ID it serves works. When no model is set, qwed verify and qwed interactive stop with an error that names the variable to set. Commands that call no model, such as qwed test, need none.
Output formats
Colorful output (default)
Quiet output (--quiet)
Error output
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 init.
Only
https URLs are accepted, including across redirects. http:// URLs are rejected before fetching. The imported YAML must contain base_url and api_key_env fields. Downloads time out after 10 seconds.Use cases
1. Quick verification
2. Scripting
3. Local development
4. Cache performance testing
Troubleshooting
”Ollama not running"
"API key required"
"Module not found”
Advanced features
Caching behavior
- Default: Enabled (24h TTL)
- Disable:
--no-cacheflag - Clear:
qwed cache clear - Stats:
qwed cache stats
Multiple providers
Related docs
- QWEDLocal guide — Python API for local verification
- Ollama integration — use free local LLMs
- LLM configuration — provider setup details