tey/standards
Tey Standards is a Laravel/PHP package that bundles opinionated coding standards and quality tooling, helping teams keep projects consistent with shared configurations for formatting, static analysis, and automated checks.
The package is a preflight/architecture gate: it runs a set of named checks and exits non-zero when something would bite you in production or violates an architecture rule. Treat it as a linter for your deployment readiness rather than for code style.
Install it as a dev dependency — it should never ship to production:
composer require --dev tey/standards
Then publish its config so the checks and rule tags live in your repo (this is the file you will actually tune over time):
php artisan vendor:publish --provider="Tey\Standards\StandardsServiceProvider"
Since the repo has no dependents and a very recent release, confirm the real surface before wiring anything up:
php artisan list | grep -i standard
Look first at:
config/standards.php or similar) — it defines which checks run, their rule tags, and any baseline/ignore paths. This is the contract you'll be editing most.--tag, --env, --baseline, --format, and what the exit codes are.First use case: run it locally against your staging config before you ever deploy.
php artisan standards:check --tag=deploy
Wire that into a composer check script alongside Pint and PHPStan on day one. The value compounds when it runs in CI, not just on your laptop.
Two distinct gates, two distinct moments. Split the tags so preflight and architecture checks run at different points:
--tag=deploy (env vars present, APP_DEBUG off, config cached, storage writable, migrations pending, queue workers configured) → runs in the CD pipeline after build, before release.--tag=arch (no env() outside config/, no DB:: in controllers, no dd()/dump(), jobs implement the right interfaces) → runs in PR CI, cheap and fast.# .github/workflows/ci.yml
- name: Architecture checks
run: php artisan standards:check --tag=arch --format=github
Keep the preflight job in your deploy workflow, not in the PR workflow — environment variables and migration state don't exist at PR time, and you'll get false failures.
Chain it with your existing quality gate. One composer script means nobody forgets it:
"scripts": {
"check": [
"@pint --test",
"@phpstan",
"php artisan standards:check --tag=arch"
]
}
Baselines for legacy code. When you introduce architecture rules into an existing app, you will have hundreds of violations on day one. Don't disable the rule — generate a baseline of current violations, commit it, and make the rule fail only on new violations. Then shrink the baseline in a dedicated PR once a quarter. If the package supports --baseline or an ignore list in config, use it exactly this way; the ratchet is the whole point.
Custom rules for your domain. The highest-leverage use is rules that encode decisions already living in someone's head:
$tries and $timeout."app/Http/Controllers may reference env()."$fillable or $guarded explicitly."->change() without doctrine/dbal."Each of these is a bug that would otherwise be caught in review — or in production. If the package exposes a base rule class, extend it and register the class in the published config; if it only ships built-in checks, keep these in PHPStan custom rules and let tey/standards own the deployment half.
Use tags as a taxonomy, not a checklist. Design your own tag vocabulary early (deploy, arch, security, data) and apply it consistently. Six months from now, when someone asks "can we ship?", --tag=deploy should be the literal answer. If the built-in tags don't map to your team's vocabulary, remap them in config rather than teaching people a second set of names.
Local pre-push hook. Run the fast tag in a pre-push hook so developers get the failure in seconds rather than after a CI round-trip:
# .git/hooks/pre-push
php artisan standards:check --tag=arch --quiet || {
echo "Architecture checks failed. Run 'php artisan standards:check --tag=arch -v' for detail."
exit 1
}
Keep deploy-tagged checks out of this hook — they need real environment context and will just be noise locally.
env() and config caching are the classic trap. Any preflight check that reads configuration must read it the way production does. If your app runs php artisan config:cache during deploy, a check that calls env('SOME_KEY') directly will behave differently from one reading config('services.key'). Verify the check runs after config:cache in your pipeline, or it's testing a configuration that will never exist at runtime.
Preflight must run against the target environment, not your local one. The single most common misuse is running --tag=deploy on a developer machine, where .env is full of values production doesn't have. Either pass the environment explicitly, or run the command inside the deploy container after artifacts are in place but before traffic is switched. If the package has no --env flag, run it as a step in the release container and keep it out of local scripts entirely.
Exit codes are the API. Confirm the command returns non-zero on failure and check whether it distinguishes "failed" from "errored" (e.g., 1 vs 2). CI only cares about zero/non-zero, but a wrapper script that wants to treat "couldn't run" differently from "found problems" needs the distinction. Test it once explicitly:
php artisan standards:check; echo "exit: $?"
Beware false positives on generated and vendored code. Scan paths should exclude vendor/, node_modules/, storage/framework/, bootstrap/cache/, and anything IDE-generated. If the config doesn't expose an exclude list, check whether the package respects a .gitignore-style file or a paths key. This is the difference between a tool people trust and one they --no-verify past.
A 0-star, single-release package means you are the QA. Pin the version in composer.json (a ^ constraint on a 0.x or freshly-released package will bite you), read the source of any rule you depend on, and wrap the CI step so a broken check doesn't block an urgent hotfix. Consider continue-on-error: false for PR checks but a separate, manually-triggerable job for the deploy gate if you need a documented bypass path.
Debug with verbosity, not by disabling rules. Use -v/-vv to see which checks ran and which were skipped — silently-skipped checks are the most dangerous failure mode, since the pipeline goes green while nothing was validated. If a check is being skipped because of a tag mismatch or environment guard, fix the tag rather than deleting the rule.
Rule tags are easy to typo and have no type system. A --tag=deply silently runs zero checks and exits 0. Guard against this by asserting a minimum number of executed checks in CI, or run the full suite (no tag filter) in at least one job so a mis-tagged rule can't hide indefinitely.
Don't let it become a substitute for the deploy steps themselves. Preflight answers "is the app configured to run?" — it cannot verify that the previous deploy actually succeeded, that the DB replica is healthy, or that the load balancer will drain connections. Keep real health checks and smoke tests downstream; treat this as a fast static gate that catches the embarrassing stuff (debug on, missing key, uncached config) before you page anyone.
How can I help you explore Laravel packages today?