- π€ LLM usage: $7.5000 (58 commits)
- π€ Human dev: ~$1974 (19.7h @ $100/h, 30min dedup)
Generated on 2026-04-26 using openrouter/qwen/qwen3-coder-next
Automatic Python prefactoring toolkit β detect, fix, and validate common code issues introduced by LLMs and humans alike.
When using LLMs for code generation, they often silently change import paths from absolute to deep relative:
# β LLM introduces this
from ....llm.generator import generate_strategy
from ....loaders.yaml_loader import save_strategy_yaml
# β
You wanted this
from planfile.llm.generator import generate_strategy
from planfile.loaders.yaml_loader import save_strategy_yamlprefact automatically detects, fixes, and validates such issues in a three-phase pipeline.
| Rule | ID | Auto-fix | Description |
|---|---|---|---|
| Relative β Absolute imports | relative-imports |
β | Converts from ....x import y to from pkg.x import y |
| Unused imports | unused-imports |
β | Removes imports never referenced in the module |
| Duplicate imports | duplicate-imports |
β | Removes the same name imported twice |
| Wildcard imports | wildcard-imports |
π | Flags from x import * |
| Unsorted imports | sorted-imports |
π | Flags import blocks not ordered stdlibβ3rd-partyβlocal |
| String concatenation | string-concat |
π | Flags "Hello " + name β suggests f-strings |
| Missing return types | missing-return-type |
π | Flags public functions without return type hints |
β = auto-fix Β· π = scan-only (report)
- Parallel Processing: Scans files in parallel when enabled
- Smart Filtering: Automatically skips large files (>100KB) and empty files
- Optimized Scanning: Excludes test directories and examples by default
- Deduplication: Prevents duplicate tickets and TODO entries
The examples/ directory contains comprehensive examples for different use cases:
| Example | Description |
|---|---|
| sample-project | Realistic project with all issues demonstrated |
| 01-individual-rules | Each rule explained with before/after code |
| 02-multiple-rules | Combining multiple rules for comprehensive cleanup |
| 03-output-formats | Console vs JSON output examples |
| 04-custom-rules | Writing your own prefactoring rules |
| 05-ci-cd | GitHub Actions, GitLab CI, Azure DevOps configs |
| 06-api-usage | Using prefact programmatically from Python |
# Try the sample project
cd examples/sample-project
prefact scan --path . --config prefact.yaml
prefact fix --path . --config prefact.yamlSee examples/README.md for a detailed guide to all examples.
pip install -e .
# with dev dependencies (pytest)
pip install -e ".[dev]"# Generate config file
prefact init
# List all available rules
prefact rules
# Scan only (no changes)
prefact scan --path ./my_project --package mypackage
# Fix + validate (with backups)
prefact fix --path ./my_project --package mypackage
# Dry-run (show what would change)
prefact fix --path ./my_project --package mypackage --dry-run
# Check a single file
prefact check ./my_project/src/mypackage/core/service.py --package mypackage
# JSON output for CI
prefact fix --path . --format json -o report.jsonπ Want to see prefact in action? Check out our comprehensive examples with real-world scenarios!
βββββββββββ βββββββββββ ββββββββββββββ
β SCAN β βββ β FIX β βββ β VALIDATE β
β β β β β β
β Detect β β Apply β β Syntax OK? β
β issues β β fixes β β Regressionsβ
β per ruleβ β + backupβ β preserved? β
βββββββββββ βββββββββββ ββββββββββββββ
- Scan β each rule walks the AST / CST and emits
Issueobjects - Fix β rules with auto-fix transform the source (via
libcstfor formatting-safe changes) - Validate β post-fix checks: syntax valid, no regressions, import counts preserved
Create prefact.yaml (auto-generated via prefact init):
package_name: planfile
include:
- "**/*.py"
exclude:
- "**/venv/**"
- "**/build/**"
- "**/tests/**"
- "**/test*/**"
- "**/examples/**"
tools:
parallel: true
cache: true
performance:
max_workers: 4
rules:
relative-imports:
enabled: true
severity: warning
unused-imports:
enabled: true
severity: info
duplicate-imports:
enabled: true
wildcard-imports:
enabled: true
severity: error
sorted-imports:
enabled: false
string-concat:
enabled: true
missing-return-type:
enabled: falsePrefact includes an autonomous mode that automatically:
- Scans your project for issues
- Generates TODO.md with all found issues
- Creates tickets in planfile.yaml for tracking
- Updates CHANGELOG.md with fixes
- Optionally runs TestQL scenarios and bridges failures into tickets
# Run full autonomous workflow
prefact -a
# Or skip tests/examples for faster runs
prefact -a --skip-tests --skip-examples
# Include TestQL validation as the final step
prefact -a --with-testql
# Use a custom directory for *.testql.toon.yaml scenarios
prefact -a --with-testql --testql-dir ./testql-scenariosPrefact can run TestQL DSL validation scenarios and bridge failing checks directly into planfile tickets, TODO.md, and configured backends (GitHub, GitLab, Jira).
# Validate a scenario and create/sync tickets
prefact testql testql-scenarios/smoke.testql.toon.yaml
# Dry-run: validate without creating tickets
prefact testql testql-scenarios/smoke.testql.toon.yaml --dry-run
# Custom project root and strategy
prefact testql scenarios/api.testql.toon.yaml -p ./my-api -s my-api/planfile.yaml
# Limit ticket generation and disable sync
prefact testql scenarios/api.testql.toon.yaml --max-tickets 10 --no-sync| Option | Default | Description |
|---|---|---|
-p, --path |
. |
Project root directory |
--url |
http://localhost:8101 |
TestQL service base URL |
--dry-run |
False |
Parse/validate only |
-s, --strategy |
<project>/planfile.yaml |
Target planfile YAML |
--create-tickets / --no-create-tickets |
True |
Create tickets for failures |
--sync / --no-sync |
True |
Sync to TODO.md and integrations |
--max-tickets |
25 |
Max tickets per run |
--testql-bin |
testql |
TestQL CLI executable |
--testql-repo-path |
/home/tom/github/oqlos/testql |
Fallback local repo path |
When creating tickets, prefact uses identity-aware deduplication based on:
- Ticket
id/ticket_id - Integration-specific IDs (
github_id,gitlab_id,jira_id) - Keys (
github_key,gitlab_key,jira_key) - URLs (
github_url,gitlab_url,jira_url,external_url) sourceandexternal_refsmetadata
If a ticket already exists with any matching identity key, it is skipped to avoid duplicates.
Recent updates have significantly improved performance:
- Parallel Processing: Scans files using multiple workers (configurable)
- Smart Filtering: Skips large files (>100KB) and files with minimal content
- Optimized Exclusions: Automatically excludes test directories and examples
- Deduplication: Prevents duplicate tickets and TODO entries across runs
from pathlib import Path
from prefact.config import Config
from prefact.engine import RefactoringEngine
config = Config(
project_root=Path("./my_project"),
package_name="planfile",
dry_run=False,
backup=True,
)
engine = RefactoringEngine(config)
result = engine.run()
print(f"Found {result.total_issues} issues")
print(f"Fixed {result.total_fixed}")
print(f"All valid: {result.all_valid}")Extend BaseRule and use the @register decorator:
from prefact.rules import BaseRule, register
from prefact.models import Issue, Fix, ValidationResult
@register
class MyCustomRule(BaseRule):
rule_id = "my-custom-rule"
description = "Does something useful."
def scan_file(self, path, source):
# Return list[Issue]
...
def fix(self, path, source, issues):
# Return (fixed_source, list[Fix])
...
def validate(self, path, original, fixed):
# Return ValidationResult
...# GitHub Actions
- name: prefact check
run: |
pip install ./prefact
prefact scan --path . --format json -o prefact-report.json
prefact fix --path . --dry-runpip install -e ".[dev]"
pytest -vLicensed under Apache-2.0.
Tom Sapletta
Last updated by taskill at 2026-04-25 13:43 UTC
| Metric | Value |
|---|---|
| HEAD | 0aac827 |
| Coverage | β |
| Failing tests | β |
| Commits in last cycle | 50 |
Primarily documentation and refactoring work: the docs and README were updated, the code-analysis engine and configuration/CLI were refactored and improved, and Markdown output and example modules were added. Minor fixes include suppressing mypy errors with type: ignore and auto-fixing ruff formatting and imports.
