Untested edge cases
will bite you
in production.
Quell finds them first.
Run quell find src/ and get three buckets back: tests written to disk, stubs to finish, and gaps with a one-line reason. Every WRITTEN test passed five gates — including proving it actually catches the bug.
Three buckets.
Nothing dropped silently.
Fully generated, verified to pass on correct code and fail when the guard is removed. Written to your test file via libcst — no string pasting.
# tests/test_payments.pydef test_payment_rejects_zero_amount():with pytest.raises(ValueError):process_payment(amount=0, currency="USD")# ✓ WRITTEN — all 5 gates passed
Source file restored immediately after gate 5 verification.
Gate 1-3 passed but gate 4 or 5 could not be verified automatically. Quell writes a stub with a clear comment on what's needed — you fill in the rest.
# tests/test_payments.pydef test_refund_idempotency():# TODO: verify idempotent refund behavior# Quell: external state makes gate 5 unprovablepass # complete me# ~ SCAFFOLDED — gates 1-3 passed
Stubs are valid Python — they run (and fail) immediately.
The requirement exists and is documented, but no automatable test path exists. Quell explains why — side effects, non-determinism, external service — so you can decide.
# FLAGGED requirements:✗ test_external_payment_gatewayReason: calls stripe.Charge.create()Side effect detected — cannot inject violation# -5 PRS per unflagged requirement
Each flagged item documents exactly why it cannot be auto-tested.
One number.
How production-ready
are your edge cases?
PRS (0–100) aggregates how many of your requirements have verified tests. It rewards WRITTEN tests, penalizes uncovered gaps, and gives partial credit for SCAFFOLDED stubs. One number in CI.
# pyproject.toml[tool.quell]prs_threshold = 80fail_on_below_threshold = true# CI gate — fails if PRS < 80$ quell score --gatePRS: 84/100 Production Ready ✓
From spec to verified test
in a few seconds.
Read existing specs
Quell AST-scans your source files. No annotations required. It reads Python docstrings (numpy/google/plain), Pydantic model field validators and constraints, and PySpark StructType schemas. Each reader returns [] on any error — it never crashes.
# quell reads what's already thereclass PaymentRequest(BaseModel):amount: float = Field(gt=0, description="Must be positive")currency: str = Field(min_length=3, max_length=3)# Extracted: MUST_RAISE, BOUNDARY, ENUM_VALID
Rule engine generates candidates
~75% of cases are handled by the deterministic rule engine — no LLM, no network. Rules handle MUST_RAISE, MUST_RETURN, BOUNDARY, ENUM_VALID, NOT_NULL, and TYPE_CHECK constraints. LLM is only called as a fallback for complex cases.
# Rule engine: BOUNDARY constraint# From: amount: float = Field(gt=0)# Generates:def test_payment_rejects_zero_amount():with pytest.raises(ValidationError):PaymentRequest(amount=0, currency='USD')
5-gate verification pipeline
Every candidate test runs the 5-gate pipeline. Gates 1-3 are static (AST valid, not duplicate, no side effects). Gate 4 runs the test on the original code — it must pass. Gate 5 injects a violation and runs again — it must fail. Gate 5 is the moat.
Gate 1: AST Valid ✓ parsesGate 2: Original ✓ not duplicateGate 3: Secure ✓ no side effectsGate 4: Passes correct ✓ test passesGate 5: Fails violated ✓ violation caught→ WRITTEN (5/5 gates)
Written to disk with libcst
Tests that pass all 5 gates are injected into your test file using libcst — Concrete Syntax Tree safe injection. No string concatenation, no overwriting. Quell backs up the file before writing, validates the CST, and restores on any failure. An audit log entry is appended.
# libcst injection — CST-safe$ quell find src/→ tests/test_payments.py (+8 tests)→ tests/test_users.py (+3 tests)Audit log: .quell/audit.jsonlBackup: .quell/backups/
Every WRITTEN test passes five gates.
Most tools run one.
# Gate 4: test on ORIGINAL codedef process_payment(amount: float):if amount <= 0: # guard intactraise ValueError('amount must be positive')$ pytest test_payment_rejects_zero_amountPASSED ✓ (gate 4 passed)
# Gate 5: test on VIOLATED codedef process_payment(amount: float):# if amount <= 0: <- guard removed# raise ValueError <- violationpass # nothing raised$ pytest test_payment_rejects_zero_amountFAILED ✗ (gate 5 passed — bug caught)
High coverage. Low PRS.
Both can be true simultaneously.
Coverage tells you which lines executed. It says nothing about whether those lines have any checks at the edge cases that matter. A 91% coverage score can coexist with a 52 PRS — same codebase, same tests, different measures.
| Constraint | What it checks | Violation injection |
|---|---|---|
| MUST_RAISE | Expected exception | Remove raise statement |
| MUST_RETURN | Expected return value | Change return to wrong value |
| BOUNDARY | Numeric boundary check | Negate comparison operator |
| ENUM_VALID | Allowed set membership | Remove enum validation |
| NOT_NULL | None rejection | Remove None check |
No annotations needed.
Quell reads what's already there.
Your docstrings, type annotations, and schema definitions already contain testable requirements. Quell extracts them without any changes to your source code.
def process_payment(amount: float):"""Process a payment.Args:amount: Must be > 0. Raises ValueErrorif zero or negative."""# → MUST_RAISE (ValueError, amount <= 0)
class OrderRequest(BaseModel):quantity: int = Field(ge=1, le=999)sku: str = Field(min_length=6, max_length=12)status: Literal['new','paid','shipped']# → BOUNDARY, ENUM_VALID, TYPE_CHECK
schema = StructType([StructField('user_id', LongType(), nullable=False),StructField('amount', DoubleType(), nullable=False),StructField('currency', StringType(), nullable=True),])# → NOT_NULL (user_id, amount)
OpenAPI, TypeScript types, and mutation results are on the roadmap.
Most tools run one gate.
We run five.
| Feature | Quell quelltest | GitHub Copilot | Qodo (CodiumAI) | Hypothesis |
|---|---|---|---|---|
| Reads existing specs (no annotation) | ✓ | ✗ | ✗ | ✗ |
| Deterministic rule engine (no LLM needed) | ✓ | ✗ | ✗ | ✓ |
| Gate 4: test passes on correct code | ✓ | partial | partial | ✗ |
| Gate 5: test fails on violated code | ✓ | ✗ | ✗ | ✗ |
| Works offline (no network required) | ✓ | ✗ | ✗ | ✓ |
| Writes verified tests to disk (libcst) | ✓ | ✗ | ✗ | ✗ |
| Three-bucket output (WRITTEN / SCAFFOLDED / FLAGGED) | ✓ | ✗ | ✗ | ✗ |
| PRS production readiness score | ✓ | ✗ | ✗ | ✗ |
| No LLM API key required | ✓ | ✗ | ✗ | ✓ |
| Source file restore guarantee (finally block) | ✓ | ✗ | ✗ | ✗ |
| Supports Pydantic + PySpark schemas | ✓ | ✗ | partial | ✗ |
| MIT licensed, runs in CI | ✓ | ✗ | ✗ | ✓ |
Comparison as of May 2026. Information sourced from public documentation.
Free to start.
Scale when you need to.
For individuals exploring Quell on personal projects.
- ✓500 verifications / month
- ✓Python docstrings + Pydantic
- ✓3-bucket output
- ✓CLI access
- ✓Community support
- ✓MIT licensed
For individual developers shipping production Python.
- ✓Unlimited verifications
- ✓All spec sources (Pydantic, PySpark, docstrings)
- ✓PRS score + CI gate
- ✓Priority rule engine updates
- ✓GitHub Actions integration
- ✓Email support
For teams that need shared PRS tracking and audit logs.
- ✓Everything in Pro
- ✓Up to 10 team members
- ✓Shared PRS dashboard
- ✓Audit log export
- ✓Dedicated support
All plans include the offline rule engine. No LLM API key required for any tier. Cancel anytime.
Questions, answered.
Stop shipping
untested edge cases.
Quell reads your existing specs, generates verified tests, and writes them to disk. No LLM key. No internet. No guessing whether your tests actually catch bugs — they do.
pip install quelltestMIT licensed · Python 3.11+ · runs offline · no LLM key required