StableStack
Catch the subtle bugs AI assistants introduce.
A lightweight linter that catches issues traditional linters miss — non-determinism that breaks LLM caching, silent exception swallowing, async mistakes, SSR pitfalls, and more. 146 rules across 23 categories, with first-class support for Python, JavaScript/TypeScript, and C# (including Unity).
Marketing site: stablestack.ai
Install
# Python (recommended)
pip install stablestack
# Node.js — thin wrapper around the pip package
npx stablestack
After upgrading, pin the version — pip caches aggressively:
pip install stablestack==0.3.26
Quick Start
# Check your source directory
stablestack src/
# Check specific files
stablestack app.py utils.py
# CI mode (exit 1 on errors)
stablestack src/ --ci
# JSON output
stablestack src/ --format json > results.json
# Only run critical rules
stablestack src/ --tier critical
# List every available rule
stablestack --list-rules
# Explain a specific rule
stablestack explain DET001
Claude Code Integration
StableStack ships opt-in Claude Code slash commands. Run once per repo:
stablestack init # pyproject.toml + .stablestackignore + /check, /fix-production slash commands
stablestack init --minimal # just pyproject.toml
stablestack init --no-commands # skip the slash commands
After init, inside Claude Code you can use:
/check— run StableStack and fix findings/fix-production— detect your CI/CD platform, monitor builds, and keep fixing until production is green
StableStack never writes files to your repo unless you run init explicitly.
Workflow Blueprints
Beyond checking code, StableStack scaffolds the process around it:
stablestack add-ci # CI + deploy pipelines, detected from your repo
stablestack add-playwright # starter E2E suite with anti-flake rules baked in
add-ci reads the repo before it writes — package manager (with a
--package-manager override when multiple lockfiles make it ambiguous),
typecheck/test/lint scripts, Prisma, Python/pytest, your deploy platform
(Vercel, Amplify, Netlify, Render, Fly, Docker), and any CI that already
exists. It refuses to write GitHub Actions into a GitLab/Bitbucket/CircleCI
repo and leaves existing deploy workflows untouched. It generates:
ci.yml— the PR gate: lint, typecheck, unit tests, the StableStack quality gate (baseline-aware, so legacy code adopts today), and E2E if a suite exists. Red blocks the merge.deploy-staging.yml— every push tomainlands on staging; a polling health check verifies the deployed site (never just the deploy's exit code) and the Playwright suite runs against the deployed staging URL.deploy-production.yml— ships when theproductionbranch advances. Promotion is a fast-forward (git push origin main:production), or automatic after green staging E2E with--auto-promote. Uses GitHub'sproductionenvironment, so adding required reviewers gives an approval gate. Verifies the live site and tags every deploy.
Platforms that auto-deploy on push (Vercel & co.) get verify-only jobs instead of duplicate deploys; anything else gets a deploy step that fails loudly until you wire in your deploy command.
add-playwright writes a config plus three starter specs: every core page
renders with zero console errors, the sitemap contract, and a money-path
template. Setting BASE_URL points the same suite at a deployed
environment — that's what the staging E2E job does.
Both are one-shot generators: the output is plain YAML/TypeScript in your repo, yours to edit.
Language Support
| Language | Extensions | Notes |
|---|---|---|
| Python | .py |
Primary language, most checkers |
| TypeScript / JavaScript | .ts, .tsx, .js, .jsx, .vue |
Frontend + backend (Next.js, tRPC, Prisma, React) |
| C# | .cs |
.NET and Unity — includes 3 Unity-specific checkers (async void, Debug.Log in production, expensive lookups in Update loops) |
| Go, Rust, Ruby | .go, .rs, .rb |
Partial coverage (hardcoded secrets, exception swallowing) |
What It Catches
Full reference: stablestack --list-rules
| Category | Prefix | Rules | Example concerns |
|---|---|---|---|
| Quality | QUAL | 19 | Exception swallowing, mutable defaults, magic numbers, complexity, print statements |
| Security | SEC | 16 | Hardcoded secrets, SQL injection, eval(), XSS, CSRF, email header injection |
| Type Safety | TYPE | 15 | Weak typing, any, env non-null assertions, unsafe JSON parsing |
| Frontend | FRONT | 13 | SSR-unsafe window, inline JSX handlers, stale time, unbounded AI output |
| Structure | STRUCT | 10 | Multiple classes per file, sys.path hacks, mixed frontend/backend code |
| Testing | TEST | 10 | Skipped tests, Playwright timing issues, duplicate test helpers |
| Determinism | DET | 9 | Unsorted iteration, datetime.now(), random without seed, uncached LLM calls |
| Project | PROJ | 8 | Missing CLAUDE.md, missing pyright config, beta dependencies, low test coverage |
| API | API | 7 | Unhandled errors, inconsistent naming, missing Content-Type, untyped responses |
| Performance | PERF | 7 | N+1 queries, render-blocking fonts, uninstrumented LLM calls |
| Memory | MEM | 4 | Unbounded queries, in-process accumulators, global singletons |
| Async | ASYNC | 4 | Missing await, blocking calls in async, fire-and-forget, silent .catch() |
| tRPC | TRPC | 4 | Procedures without input validation, inline Zod schemas |
| Datetime | DATE | 3 | Naive datetimes, DB timezone mismatches |
| C# | CS | 3 | async void, Debug.Log in production, expensive lookups in Unity Update |
| Concurrency | CONC | 2 | Check-then-act races, non-atomic read/write |
| Kubernetes | KUBE | 2 | Local filesystem storage, missing SSL redirect |
| Migrations | MIG | 2 | Alembic revision ids over VARCHAR(32), deploy scripts that mask migration failures |
| Rate Limiting | RATE | 2 | Missing rate limits, in-memory rate limiter |
| Schema | SCHEMA | 2 | Pydantic nullability, Pydantic/SQLAlchemy field mismatches |
| Session | SESS | 2 | DB session passed to background tasks, thread safety |
| Accessibility | A11Y | 1 | Button contrast |
| Imports | IMPORT | 1 | Imports shadowing builtins |
Free vs. Paid Tiers
- Free (24 rules) — always available, no license required. Covers critical security, schema, project setup, quality, structure, async, API, and C# checkers.
- Paid (122 rules) — unlocked with
stablestack activate <license-key>. Buy a license at stablestack.ai.
Pricing and features: stablestack.ai/pricing.
Example Output
src/cache.py
⚠ Line 42: Looping through 'config.items()' without sorting. This may produce different results on different runs.
Problem:
for key, value in config.items():
Fix:
for key, value in sorted(config.items()):
Why? Dictionary order isn't guaranteed to be the same every time your program runs.
This can cause tests to pass sometimes and fail other times, and can break caching
systems that depend on consistent output.
────────────────────────────────────────────────────────────
Found 1 warning in 1 file
Configuration
Configure StableStack in your pyproject.toml:
[tool.stablestack]
# Enable only specific rules (empty = all enabled)
enable = []
# Disable specific rules
disable = ["QUAL005", "QUAL006"]
# Path patterns
include = ["src/**/*.py"]
exclude = ["**/migrations/**", "**/test_*.py", "node_modules/**"]
# Override severity per rule
[tool.stablestack.rules.DET001]
severity = "info"
You can also add a .stablestackignore file (glob patterns, one per line) for paths the checker should skip.
CLI Options (essentials)
Usage: stablestack [OPTIONS] [PATHS]...
Options:
-f, --format [text|json|claude] Output format (default: text)
-c, --config PATH Path to pyproject.toml config
--enable TEXT Comma-separated rule IDs to enable
--disable TEXT Comma-separated rule IDs to disable
--ci Exit 1 if any errors found
-t, --tier [critical|recommended|optional|preference]
Run ONLY rules from this tier
-u, --up-to [critical|recommended|optional|preference]
Run rules up to and including this tier
--list-rules List all available rules and exit
--stats Show codebase statistics
--baseline PATH Only report issues not in baseline
--generate-baseline Generate a baseline file
--fix Automatically fix issues where possible
--dry-run Show what --fix would do
-w, --watch Watch for changes and re-run
--top INTEGER Show only the top N findings
--help Show full help
Subcommands:
stablestack init Install Claude Code commands and config files
stablestack explain Explain a specific rule (e.g. `stablestack explain DET001`)
stablestack activate Activate a paid license key
Why StableStack?
AI coding assistants are fast, but they ship patterns traditional linters don't catch:
- Non-determinism that breaks LLM caching and causes flaky tests
- Hardcoded secrets that slip into git history before review
- Silent exception swallowing that hides production bugs
- Missing
awaiton async calls that return without doing any work - SSR-unsafe code that crashes in Next.js production builds
- Unity anti-patterns like
GameObject.FindinUpdate()loops that kill frame rates - Weak types (
any,Dict[str, Any]) that bypass IDE checking
StableStack focuses specifically on the shape of bugs AI assistants generate.
Repository Structure
| Directory | Description |
|---|---|
/stablestack |
Core product — the Python CLI and analysis engine (published to PyPI) |
/npm-package |
Thin Node.js wrapper that shells out to the Python CLI (npx stablestack) |
/nuget-package |
Prototype dotnet tool wrapper for .NET / Unity developers (not yet published) |
/site |
Marketing site at stablestack.ai (Next.js) |
/infrastructure/license-api |
AWS Lambda API for license validation + anonymous telemetry (Terraform) |
Development Setup
Running tests
cd stablestack
PYTHONPATH=src python -m pytest tests/ -v
Running the site locally
cd site
npm install
npm run dev
Secrets management
This project uses Doppler for secrets. Never commit .env files.
brew install dopplerhq/cli/doppler
doppler login --scope /path/to/vibecheck
doppler setup
# Run commands with secrets injected
doppler run -- stablestack src/
Ask a team member to add you to the CTS workspace in Doppler.
Contributing
See CONTRIBUTING.md.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stablestack-0.3.30.tar.gz.
File metadata
- Download URL: stablestack-0.3.30.tar.gz
- Upload date:
- Size: 351.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2055e8f04a304dade4fb675751dfb9be26c1a817f6ddae38134972d0d3008464
|
|
| MD5 |
27a06c194899235aa601c23414788012
|
|
| BLAKE2b-256 |
2201ac5446a5c80717cb55445c7634ecc10870b0c23e1d2eb44a048a5fa39003
|
File details
Details for the file stablestack-0.3.30-py3-none-any.whl.
File metadata
- Download URL: stablestack-0.3.30-py3-none-any.whl
- Upload date:
- Size: 265.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99b519874a21672c0802c6e0e5d38540c5b33fe0d38f55b060a32492e97ed3b9
|
|
| MD5 |
a218ffb45cbc7e09deafd138fc7cd154
|
|
| BLAKE2b-256 |
bb31471572a1c180931fe4065597d8780561ba221924c43abd4064df17270ca5
|