You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Right now most behavior is configured via CLI flags, env vars (DESLOPPIFY_PMD_THREADS, etc.), and per-invocation commands (desloppify exclude <path>). For anything that's reused across runs — strict-mode threshold, disabled domains/detectors, exclude lists, runner choice, custom thresholds — you have to either remember to pass the flags every time or wrap things in a Makefile/CI script.
It would be great to have a real configuration file that desloppify reads automatically, with sensible cross-platform discovery rules and a documented schema.
Motivation
Concrete things that today require flags, env vars, or repeated commands but would be one-time settings in a config file:
Disabling whole domains/detectors a project doesn't want (e.g. issue Can I disable a specific domain? #501 — user wants to disable the test_coverage domain entirely)
Tweaking thresholds for large_files_threshold, complexity, duplication, etc. without per-run flags
Choosing strict vs lenient as the default target, and the numeric target score
A persistent exclude list that doesn't depend on running desloppify exclude <path> per machine
Per-language overrides for monorepo-ish setups (the README explicitly says you must scan each project separately — config could capture each project's preferences)
CI vs local profile defaults (right now you pass --profile ci --no-badge every time)
PMD thread count, runner selection, review batching, etc.
Proposed Behavior
File format
TOML, to match the Python ecosystem (pyproject.toml, ruff, mypy via mypy.ini/pyproject, etc.) and so it can be parsed with stdlib tomllib on Python 3.11+ without an extra dep.
Two scopes
Project config — lives in the repo, committed, shared by everyone working on it.
User config — per-user defaults that apply when no project config overrides them. Useful for things like "always use this runner" or "never enable the badge locally".
Project config wins over user config; CLI flags and env vars still win over both. Precedence (highest to lowest):
CLI flags
Environment variables
Project config
User config
Built-in defaults
Discovery — follow each OS's conventions
Project config (searched from --path upward to the repo root or filesystem root, first match wins):
.desloppify.toml
desloppify.toml
[tool.desloppify] table inside pyproject.toml
User config — respect the platform spec on each OS:
Linux / BSD: XDG Base Directory spec
$XDG_CONFIG_HOME/desloppify/config.toml, falling back to ~/.config/desloppify/config.toml
DESLOPPIFY_CONFIG env var (and a --config <path> CLI flag) should override discovery entirely for power users and CI.
Implementation note: platformdirs is the standard cross-platform library that already encodes these conventions correctly — recommend using it rather than rolling per-OS path logic by hand.
Example schema
# .desloppify.toml — project config
[general]
# default target the agent works towardtarget_score = 98# which score mode to enforce/report by defaultstrict = true# fail nonzero if score is below target when running `status` / CIenforce_target = true# global runner override (claude, codex, etc.)runner = "claude"
[scan]
# baseline excludes — equivalent to running `desloppify exclude <path>` once per entryexclude = [
"vendor/",
"node_modules/",
"dist/",
".worktrees/",
"build/",
]
# CI-equivalent flags so you don't have to repeat --profile ci --no-badgeprofile = "ci"badge = false
[thresholds]
large_files = 600complexity_warn = 15complexity_error = 25duplication_min_lines = 40
[domains]
# disable whole domains (addresses #501)disabled = ["test_coverage"]
[detectors]
# finer-grained: disable specific detectors without nuking the whole domaindisabled = ["unused::unused_import", "cycles"]
[detectors.large_files]
# per-detector overridesthreshold = 800# per-language overrides — useful when one repo legitimately mixes languages
[languages.rust]
detectors.disabled = ["cycles"] # known false positives on flat module layouts (#522, #545)
[languages.python]
thresholds.large_files = 500
[review]
# subjective review configurationenabled = truebatch_size = 5# skip specific subjective dimensionsdisabled_dimensions = ["error_handling_patterns"]
[ci]
# overrides that apply when profile = "ci" or when invoked with --profile cibadge = falsefail_below = 95
Behavior details
desloppify config show — print the merged, effective config (with the source of each value) so it's debuggable.
desloppify config path — print the file paths that were searched and which one was loaded.
desloppify config init — scaffold a starter .desloppify.toml (or [tool.desloppify] in pyproject.toml) with commented defaults.
Unknown keys should be a warning, not a hard error, so newer configs don't break older desloppify versions catastrophically.
A schemaVersion (or version) key at the top so the loader can detect and migrate old configs cleanly.
JSON Schema published alongside so editors can autocomplete and validate.
Why this matters
It removes the "how was this project's desloppify configured" footgun — currently that knowledge lives in a contributor's shell history or a CI yaml.
It gives projects a single committed file to express their quality bar, which fits desloppify's whole "north-star score" framing.
It cleanly separates user preferences (runner choice, local-only excludes) from project rules (target score, disabled domains) without conflating them in the same file.
Open questions
Should [tool.desloppify] in pyproject.toml be first-class or just a convenience for Python projects? (My take: first-class, since many users of this tool are in Python projects already.)
How should multi-project monorepos express per-project config? Per---path.desloppify.toml is the obvious answer, but it might be worth supporting an array-of-tables for multiple project roots in a single root config too.
Should disabling a domain affect the score, or just hide it? (Probably affect it, otherwise it's a gaming vector — which conflicts with the anti-gaming design goal.)
Summary
Right now most behavior is configured via CLI flags, env vars (
DESLOPPIFY_PMD_THREADS, etc.), and per-invocation commands (desloppify exclude <path>). For anything that's reused across runs — strict-mode threshold, disabled domains/detectors, exclude lists, runner choice, custom thresholds — you have to either remember to pass the flags every time or wrap things in a Makefile/CI script.It would be great to have a real configuration file that desloppify reads automatically, with sensible cross-platform discovery rules and a documented schema.
Motivation
Concrete things that today require flags, env vars, or repeated commands but would be one-time settings in a config file:
test_coveragedomain entirely)large_files_threshold, complexity, duplication, etc. without per-run flagsdesloppify exclude <path>per machine--profile ci --no-badgeevery time)Proposed Behavior
File format
TOML, to match the Python ecosystem (
pyproject.toml,ruff,mypyviamypy.ini/pyproject, etc.) and so it can be parsed with stdlibtomllibon Python 3.11+ without an extra dep.Two scopes
Project config wins over user config; CLI flags and env vars still win over both. Precedence (highest to lowest):
Discovery — follow each OS's conventions
Project config (searched from
--pathupward to the repo root or filesystem root, first match wins):.desloppify.tomldesloppify.toml[tool.desloppify]table insidepyproject.tomlUser config — respect the platform spec on each OS:
$XDG_CONFIG_HOME/desloppify/config.toml, falling back to~/.config/desloppify/config.toml~/Library/Application Support/desloppify/config.toml~/.config/desloppify/config.tomlas a secondary path, since many devs on macOS prefer XDG layout%APPDATA%%APPDATA%\desloppify\config.toml(i.e.C:\Users\<user>\AppData\Roaming\desloppify\config.toml)DESLOPPIFY_CONFIGenv var (and a--config <path>CLI flag) should override discovery entirely for power users and CI.Implementation note:
platformdirsis the standard cross-platform library that already encodes these conventions correctly — recommend using it rather than rolling per-OS path logic by hand.Example schema
Behavior details
desloppify config show— print the merged, effective config (with the source of each value) so it's debuggable.desloppify config path— print the file paths that were searched and which one was loaded.desloppify config init— scaffold a starter.desloppify.toml(or[tool.desloppify]inpyproject.toml) with commented defaults.schemaVersion(orversion) key at the top so the loader can detect and migrate old configs cleanly.Why this matters
cyclesdetector false positives for Rust module system #522,cyclesdetector flags legitimate flat-module binary crate layouts as import cycles #545) by making the workaround declarative and persistent instead of imperative-per-run.Open questions
[tool.desloppify]inpyproject.tomlbe first-class or just a convenience for Python projects? (My take: first-class, since many users of this tool are in Python projects already.)--path.desloppify.tomlis the obvious answer, but it might be worth supporting an array-of-tables for multiple project roots in a single root config too.