This guide walks you through using propcheck on a real project — from setup to CI integration.
Time: 5 minutes | Cost: Free with --mock, ~$0.05/file with real AI
npm install -D propcheck typescript
npx propcheck initThat's it. init creates .propcheck/ and updates your .gitignore automatically.
Pick any file in your project with exported functions:
npx propcheck infer --mock src/utils.tsYou'll see output like:
Analyzing 3 functions in src/utils.ts...
Validating 9 rules (quick test, 100 random inputs each)...
Discovered 9 rules for src/utils.ts ($0.00, 0.0s)
* clamp: clamp should return a finite number ★ 13/13
* clamp: Applying clamp twice equals once ★ 11/13 [risky]
* unique: unique output length ≤ input length ★ 13/13
What happened:
- propcheck analyzed your function signatures
- Generated "rules" — properties that should always be true
- Ran 100 random inputs against each rule to verify
npx propcheck run src/utils.tsThis throws 1,000 random inputs at each rule. If something fails, you'll see the exact input that broke it:
✖ calculateTotal: Total should be non-negative FAILED
Counterexample: calculateTotal([-Infinity, 100])
Shrunk in 3 steps
Mock mode generates properties from function signatures alone. Real AI reads your actual code and generates much smarter properties — it understands your business logic.
# Anthropic (direct)
export PROPCHECK_API_KEY=sk-ant-... # From console.anthropic.com
npx propcheck infer src/utils.ts
# OpenRouter, one-api, or any OpenAI-compatible endpoint
PROPCHECK_API_KEY=sk-or-... npx propcheck infer \
--provider openai-compatible \
--base-url https://openrouter.ai/api/v1 \
src/utils.tsCost: ~$0.05 per file, one-time. After inference, all runs are free.
Privacy: Code is sent to the AI only during infer. All testing runs 100% locally.
npx propcheck props # List all rules
npx propcheck props --status risky # Show only risky ones
npx propcheck property src/utils.ts prop_001 # Inspect detailsIf a rule is too flaky for CI:
npx propcheck property src/utils.ts prop_003 --status quarantinedCreate .github/workflows/propcheck.yml:
name: propcheck
on: [pull_request]
jobs:
propcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: "20" }
- run: npm ci
- run: npx propcheck run --changed --json > propcheck-results.json
- run: npx propcheck badgeKey flags for CI:
--changed— only test files modified in the PR--json— machine-readable output--quick— 100 inputs (faster CI) vs default 1,000
When propcheck finds a bug:
npx propcheck fix src/utils.ts # AI diagnoses and suggests fix
npx propcheck fix --apply src/utils.ts # Apply the fix automaticallynpx propcheck infer --mock src/
npx propcheck run src/npx propcheck infer --mock --function calculateTotal,applyDiscount src/cart.tsnpx propcheck run --seed 42 src/utils.tsCreate .propcheckrc in your project root:
{
"minScore": 10,
"maxProperties": 5,
"numRuns": 1000,
"storeDir": ".propcheck"
}propcheck run --json outputs:
{
"version": "0.4.0",
"timestamp": "2026-04-07T12:00:00.000Z",
"filePath": "src/cart.ts",
"summary": {
"passed": 5,
"failed": 1,
"errors": 0,
"skipped": 2,
"totalIterations": 6000,
"duration": 1234
},
"passed": [
{ "propertyId": "prop_001", "iterations": 1000 }
],
"failed": [
{
"propertyId": "prop_003",
"errorMessage": "Property failed after 42 tests",
"counterexample": [150],
"shrinkSteps": 3
}
],
"errors": [],
"skipped": [
{ "propertyId": "prop_005", "reason": "quarantined" }
]
}| Exit Code | Meaning | CI Action |
|---|---|---|
0 |
All tests passed | ✅ Merge OK |
1 |
Bug found | ❌ Block merge |
2 |
Config/setup error | ❌ Fix setup |
Q: Does propcheck replace my unit tests? No. Unit tests verify specific scenarios you thought of. propcheck discovers edge cases you didn't think of. Use both.
Q: How is this different from fuzzing? Fuzzing throws random inputs at your code looking for crashes. propcheck throws random inputs looking for logical bugs — prices going negative, data corruption, broken invariants.
Q: What if a rule is wrong?
Quarantine it: propcheck property <file> <id> --status quarantined. You can also drop it permanently with --status dropped.
Q: Does it work with JavaScript?
Yes. Point at any .js file. TypeScript must be installed (it's used for analysis only).
Q: Does it work with Python?
Yes. Install Hypothesis: pip install hypothesis. Then: propcheck infer --mock app.py.