tightenco/duster
Duster automatically applies Tighten's default Laravel code style by combining TLint, PHP_CodeSniffer, PHP CS Fixer, and Pint. Lint or fix everything at once, target only uncommitted files with --dirty, and customize includes/excludes via duster.json.
The core decision it de-risks: do we adopt an opinionated code-style baseline, and if so whose? Duster is a thin orchestration wrapper that bundles four established tools (Pint, TLint, PHP_CodeSniffer, PHP CS Fixer) behind one lint / fix command and one published set of standards (pint.json, .php-cs-fixer.dist.php, .phpcs.xml.dist, style guide). It converts a recurring, unbounded committee debate into a 30-minute install decision.
Build vs. buy
cwd handling, glob handling, PHP version support drops (v2.0.0 dropped PHP 8.0), and dependency bumps (releases show repeated Guzzle/PHPCS updates). That churn is the real cost Duster absorbs for you.Use cases worth estimating and instrumenting
duster fix --dirty lets you burn down style debt incrementally on touched files only, rather than an unreviewable mega-commit.duster lint as a required check; the companion GitHub Action (and duster github-actions stub publishing) removes pipeline scaffolding work.--using="phpstan,tlint,pint" and the scripts block in duster.json let you pull adjacent checks (e.g., static analysis) into the same gate without a second orchestration layer.--env=ddev|warden|lando|sail means local and CI invoke the same toolchain — removes a whole class of "works on my machine" format diffs.What it explicitly does not decide — keep these separate on the roadmap: static analysis depth, security/dependency auditing, test coverage thresholds, architecture/layering enforcement. The biggest product risk here is organizational conflation: "we run Duster, so we have quality gates." Duster is formatter/lint hygiene, not correctness.
Adopt when all of these hold
require --dev dependency is acceptable and dev-only risk tolerance exists.Tells that you need this now: PRs dominated by whitespace/import-order/class-element-order nits; repeated reviewer debates on the same trivialities; inconsistent env() usage across services.
Look elsewhere when
workflow_run. This is an ops-design decision, not a footnote.Risks to carry explicitly
env() ban with tests excluded) mean every deviation becomes duster.json plus per-tool config sprawl — config surface grows faster than the value.composer remove + a CI step swap, and the most portable asset (the standards files) can be snapshotted into your repo.Executives (60 seconds). One dev-only dependency that ends the "how should our Laravel code look" debate and gives every engineer and every pipeline the same two commands: duster lint and duster fix. The cost is a dev dependency and roughly a day of rollout; the return is reviewer hours back, smaller and more reviewable diffs, and faster onboarding. It does not replace security scanning or static analysis — it removes the noise that hides them.
Engineering leadership. Standardizes four tools behind one command, one config file, and one published standard, with first-class support for containerized environments (Sail, ddev, warden, lando) so local and CI agree. --dirty enables incremental cleanup instead of a legacy-repo big bang. duster.json scripts lets us fold in PHPStan later without re-platforming. Cost of reversal is low and bounded.
Engineering team. Install: composer require tightenco/duster --dev. Daily loop: ./vendor/bin/duster fix --dirty before commit, lint before push. Configure includes/excludes and extra scripts in duster.json; select or reorder tools with --using. Publish GitHub Actions or Husky hooks with the built-in commands. If you disagree with a rule, propose a config change — not a per-PR exception.
How we'll know it worked (proposed success metrics). Share of PR review comments that are style-only (target: → 0); PR review turnaround time; CI lint stage duration; time-to-first-merged-PR for new hires; count of style-only bot commits (a rising count hints the local hook isn't doing its job).
Rollout sequence. Pilot on one repo in lint-only / report mode → promote the resulting duster.json plus standards files as the org baseline → flip to fix mode with workflow_run chaining → add Husky hooks and fix --dirty locally → layer PHPStan in via scripts.lint. Exit criteria: standards configs snapshot into each repo, so removal is a dependency delete plus a CI step swap.
How can I help you explore Laravel packages today?