Deterministic code quality grading for AI coding workflows.
CodeSieve runs 8 principle-based sieves against your Python, PHP, JavaScript, and TypeScript code and produces a 1-10 score per principle, with an aggregate letter grade (A-F). No LLM calls, no flaky heuristics -- just fast, reproducible static analysis powered by tree-sitter.
Built for the AI-assisted coding loop: let your agent write code, then grade it automatically before committing. Works as a CLI tool, CI gate, or quality feedback signal for any AI coding agent.
Traditional linters focus on style. CodeSieve focuses on design principles -- the things that make code maintainable, readable, and correct:
| Sieve | What it measures |
|---|---|
| KISS | Cyclomatic complexity, function length, parameter count |
| Nesting | Max and average nesting depth of control flow |
| Naming | Convention compliance (PEP 8 for Python, PSR-1/PSR-12 or WPCS for PHP), abbreviated names |
| ErrorHandling | Bare excepts, empty handlers, broad catches without re-raise |
| TypeHints | Type annotation coverage, declare(strict_types=1) for PHP (PSR-12 only) |
| MagicNumbers | Unexplained numeric literals in function bodies |
| GuardClauses | Functions wrapping entire body in a single if-block |
| DeprecatedAPI | Calls to deprecated/removed PHP functions with replacement suggestions |
| Comments | Docstring/JSDoc coverage on named functions |
| DRY | Duplicate function bodies — identical logic extracted instead of copied |
Each sieve produces a score from 1.0 (worst) to 10.0 (best), specific findings with line numbers, and an actionable summary. Scores are weighted and combined into an aggregate grade.
pip install codesieveRequires Python 3.10+.
# Scan a single file
codesieve scan app.py
codesieve scan index.php
codesieve scan app.ts
# Scan a directory (picks up .py, .php, .js, .jsx, .ts, .tsx files)
codesieve scan src/
# JSON output for CI pipelines
codesieve scan src/ --format json
# Fail CI if quality drops below threshold
codesieve scan src/ --fail-under 7.0
# Run specific sieves only
codesieve scan src/ --sieves KISS,Naming,TypeHints
# Grade PHP against the WordPress Coding Standards instead of PSR
codesieve scan wp-content/plugins/my-plugin/ --standard wordpress
codesieve scan wp-content/plugins/my-plugin/ --standard auto
# List all available sieves
codesieve sieves CodeSieve Report -- src/myapp/handlers.py (174 lines, Python)
+-----------------+---------+------------+--------------------------------------+
| Sieve | Score | Type | Summary |
+-----------------+---------+------------+--------------------------------------+
| KISS | 6.9 | determ. | avg CC=7.7, max fn length=35 |
| Nesting | 7.8 | determ. | max depth=3, avg depth=2.2 |
| Naming | 10.0 | determ. | 0 violations in 40 names (0%) |
| ErrorHandling | 10.0 | determ. | No try blocks in 6 functions |
| TypeHints | 9.5 | determ. | 94% type coverage (11/12 params) |
| MagicNumbers | 10.0 | determ. | no magic numbers |
| GuardClauses | 10.0 | determ. | all functions use good return patterns|
| DeprecatedAPI | 10.0 | determ. | No deprecated API calls found |
+-----------------+---------+------------+--------------------------------------+
| AGGREGATE | 8.9 | | Grade: A |
+-----------------+---------+------------+--------------------------------------+
CodeSieve understands PHP idioms and enforces established standards:
- PSR-1 naming: camelCase methods, PascalCase classes, UPPER_SNAKE constants -- with standard citations in findings
- PSR-12 strict types: flags files missing
declare(strict_types=1) - WordPress Coding Standards:
--standard=wordpressgrades WordPress PHP against WPCS instead of PSR (see below) - Error handling: detects empty catch blocks, broad
\Exception/\Throwablecatches without re-throw - Deprecated API detection: 24 deprecated/removed functions (mysql_, ereg,
each(),create_function(),utf8_encode(),strftime()) with specific replacement suggestions and PHP version references
WordPress code is not PSR code, and grading it as if it were produces a flood of
false positives. --standard=wordpress swaps in the WordPress Coding Standards:
| Rule | --standard=psr (default) |
--standard=wordpress |
|---|---|---|
| Functions / methods | camelCase |
snake_case |
| Classes | PascalCase |
Capitalized_Words_With_Underscores (SQ_Probe) |
| Constants | UPPER_SNAKE_CASE |
UPPER_SNAKE_CASE (no conflict) |
declare(strict_types=1) |
required (PSR-12 §2.1) | not expected |
--standard=auto decides in two steps, because the ecosystem and the naming
convention are different questions and modern WordPress code has drifted
between them:
- Which ecosystem? WordPress if the path contains
wp-content/,wp-includes/, orwp-admin/, or if the source carries at least two WordPress fingerprints (aPlugin Name:/Theme Name:header,add_action(),esc_html(),ABSPATH,WP_Query, …). - Which naming standard? Only then does it pool a vote over every
function name(declaration in the scanned files, and it picks WordPress mode only if decisively snake_case names are not outnumbered by decisively camelCase ones. Names with no case signal (render) or a mix (get_Foo) vote for neither;__constructand friends are excluded.
Step 2 exists because hybrid codebases are common: WPCS file names
(class-foo.php) and WPCS class names (Module_Base) wrapped around
predominantly PSR-style camelCase methods. On one real 110-file plugin, forcing
wordpress scored worse than the default (8.6 vs 8.8) because it flagged 737
camelCase methods. The vote resolves that plugin to psr correctly.
The vote is pooled across the whole scan, so every file in a directory is graded
against one standard rather than flip-flopping file by file. Scanning a single
file has only that file's names to go on — if you have a codebase with mixed
conventions, set standard: explicitly in .codesieve.yml rather than relying
on auto.
WordPress mode does not weaken the TypeHints coverage check — modern WP
plugins can and should declare PHP 7.4+ parameter and return types. Only the
strict_types line item is dropped. Every other sieve behaves identically.
Create a .codesieve.yml in your project root:
codesieve init# .codesieve.yml
exclude:
- "**/.venv/**"
- "**/migrations/**"
- "**/vendor/**"
weights:
KISS: 0.20
Nesting: 0.15
Naming: 0.15
ErrorHandling: 0.10
TypeHints: 0.08
MagicNumbers: 0.05
GuardClauses: 0.05
DeprecatedAPI: 0.05
fail_under: 7.0
# Coding standard to grade PHP against: psr (default) | wordpress | auto
standard: wordpressAdjust weights to match what matters most for your project. Sieves with weight 0 are skipped.
By default CodeSieve reads .codesieve.yml from the current working directory, independently of what you are scanning. That means the same target can score differently depending on where you ran the command — a CI job, a pre-commit hook, and a manual run can silently disagree.
--config-from-target keys the config off the scanned path instead:
codesieve scan /path/to/other/project/src --config-from-targetIt walks up from the target looking for .codesieve.yml, stops at the first hit or at a repo root (a .git directory), and uses plain defaults if the target tree has none — deliberately not the current directory's config, which would reintroduce the coupling the flag removes. An explicit --config always wins.
The flag is opt-in, so existing invocations are unaffected.
CodeSieve is designed as a quality gate in AI coding loops:
Agent writes code --> CodeSieve grades it --> Agent reads feedback --> Agent improves code
The JSON output (--format json) gives structured feedback that any AI agent can parse and act on. The --fail-under flag works as a CI gate to prevent quality regressions.
Add CodeSieve as a pre-commit hook:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/MarcinDudekDev/codesieve
rev: v0.1.0
hooks:
- id: codesieve
args: ["--fail-under", "7.0"]| Language | Status | Standards |
|---|---|---|
| Python | Supported | PEP 8 |
| PHP | Supported | PSR-1, PSR-12, WordPress (WPCS) — selectable via --standard |
| JavaScript | Supported | camelCase, PascalCase |
| TypeScript | Supported | camelCase, PascalCase, type annotations |
| Go | Supported | gofmt-style naming |
CodeSieve uses tree-sitter for parsing, making new language support straightforward -- each language needs its own sieve implementations that understand the language's idioms and conventions.
- Python support (8 sieves)
- PHP support (8 sieves, PSR-1/PSR-12 enforcement, deprecated API detection)
- JavaScript/TypeScript support (camelCase/PascalCase, TS type annotations)
- Go support
- Selectable coding standards (
--standard=psr|wordpress|auto) with WPCS for WordPress PHP -
--watchmode for continuous feedback - GitHub Actions integration
- Pre-commit hook
- More sieves: Comments (docstring coverage), DRY (duplicate function bodies)
- More sieves: SRP, Complexity
- Custom sieve plugins
Contributions are welcome! CodeSieve is in early development and there's plenty of room to help:
- Add a sieve -- each sieve is a self-contained class in
src/codesieve/sieves/ - Add language support -- tree-sitter grammars + language-specific sieve implementations
- Improve scoring -- better heuristics, edge case handling, calibration
- Write tests -- more fixture files, edge cases, regression tests
# Development setup
git clone https://github.com/MarcinDudekDev/codesieve.git
cd codesieve
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest tests/ -vSee the existing sieves in src/codesieve/sieves/ for the pattern -- each one extends BaseSieve and implements an analyze() method that receives a parsed AST and returns scored findings.
MIT -- see LICENSE.