Download the PHP package semitexa/laravel-ai-verify without Composer

On this page you can find all versions of the php package semitexa/laravel-ai-verify. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-ai-verify

Laravel AI Verify: stop AI agents from faking "done"

Tests Latest Version PHP

AI code verification for Laravel. Claude Code, Cursor, Codex, Copilot or Gemini says the change is done. php artisan ai:verify checks whether it is.

It runs only the tests, Larastan, Pint and Laravel boot checks the diff actually needs. It fails the change if the agent deleted, skipped or weakened a test to get green. It returns one verdict the agent must act on: pass, fail or incomplete. One more command writes the instructions into AGENTS.md and CLAUDE.md. For Claude Code it also adds a Stop hook, so the agent cannot finish while verification fails. Verified commits get a trailer that CI can check.

Before the agent edits anything, php artisan ai:graph gives it a code graph of the Laravel app. It covers routes → controllers → form requests → models → tables → policies → views → tests, and events → listeners. It also does impact analysis: what a change affects and which tests cover it.

How it works: ai:verify reads what changed (uncommitted work, a git ref, or a file list). It works out the smallest set of checks that can vouch for that change and runs them with timeouts. The verdict comes as streamed NDJSON for agents, a JSON envelope or terminal text.

Note that this run did not execute the whole suite and did not run PHPStan on the whole app. It followed the change. The edited controller handles GET /posts/{post}, and tests/Feature/PostTest.php requests that URI, so that is the test that runs.

A real catch

While the demo app for this README was being written, the RSS view started with <?xml version="1.0"?>. That is valid XML, but Blade compiles it into PHP that doesn't parse. ai:verify flagged the view, the failing FeedTest, and the controller line that rendered it. The obvious "fix" was {!! '<?xml … ?>' !!}. It still failed, because the ?> inside the string closes PHP mode in the compiled template. The run went green only after the real fix ('<'.'?xml … ?'.'>'). Without the check, an agent would most likely have reported that first fix as done.

This package is a Laravel port of ai:verify from Semitexa, a PHP framework built so that AI agents can work on it safely. Semitexa describes its own structure and checks every change. This package brings the "checks every change" half of that to Laravel.


Why

Coding agents say "done" when the code looks right. Giving them a way to check that is harder than it sounds:

ai:verify handles all of this with one command and a fixed contract:

It does So that
Classifies each changed file into a Laravel kind (controller, model, migration, Blade view, route file, config, provider, listener, …) Each kind gets the checks that can actually catch its failures
Picks tests through a project graph (tests that reference the class, request a route it handles, render a view it touches, use its factory), plus naming conventions It runs the tests that matter, not the whole suite
Boots Laravel in a fresh process for the subsystem you touched (route:list, config:cache, about, event:list) Boot-time breakage is caught before a browser hits it
Runs migrations' up()/down() in pretend mode A typo in a migration fails here, not in production
Compiles changed Blade views with your app's compiler and lints the result An unclosed @if or @forelse is reported against the .blade.php file
Blames only what you introduced: PHPStan errors on unchanged lines and Pint fixers the file already needed are reported as pre-existing and don't fail the run Legacy debt doesn't block an agent's correct change
Guards test integrity: it fails if a changed test file lost tests or assertions, or gained skip()/todo()/only() "Make the suite green by deleting the failing test" doesn't pass
Applies a coverage gap rule: pass requires at least one check to have read at least one changed file "Green" never means "nothing looked at it"
Gives restart hints: queue:restart, octane:reload, stale bootstrap/cache The agent knows that a passing verify doesn't mean running workers have the new code

Install

Requires PHP 8.3+ and Laravel 12 or 13. Larastan and Pint are used when the project has them. Pest or PHPUnit is detected automatically.

Tell your agents

An agent only uses a tool it knows about. One command puts the instructions where each agent looks:

Agent Where the instructions go
Codex, Cursor, Copilot, Amp, Jules, Zed, … AGENTS.md (always)
Claude Code CLAUDE.md (always), .claude/skills/ai-verify/, and with --hook a Stop hook
Gemini CLI GEMINI.md, if it exists
GitHub Copilot .github/copilot-instructions.md, if it exists
JetBrains Junie .junie/guidelines.md, if it exists
Cursor .cursor/rules/ai-verify.mdc, if .cursor/ exists
Windsurf .windsurf/rules/ai-verify.md, if .windsurf/ exists
Agents that read .agents/skills .agents/skills/ai-verify/, if .agents/ exists

Why the hook. An agent can ignore an instruction, but it can't ignore a Stop hook. With --hook, every time Claude Code is about to finish, ai:verify checks the uncommitted work. If the verdict is fail, Claude is sent back with the violations and fixing commands instead of stopping. To keep it from getting in the way:

With Laravel Boost, you can instead tick semitexa/laravel-ai-verify in boost:install's third-party list, or add it to "packages" in boost.json. Boost then ships the same guideline and the ai-verify skill, and ai:verify:install steps aside to avoid duplicates. --hook still applies.

php artisan about shows whether the instructions and the hook are in place.

Usage

Exit code: 0 for pass/skipped, 1 for fail/incomplete.

Scopes

Scope Runs
minimal php -l per PHP file, Blade compile, JSON validity, changed test files, test integrity
standard (default) + Pint and PHPStan on the changed files, related tests from the graph and naming, Laravel probes per kind, migration pretend-run
broad + every Laravel probe and the whole test suite

standard widens to broad on its own when a contract, a service provider, bootstrap/app.php or composer.json changes, or when 15 or more files change. Each widening is reported as an expansion event, with the reason.

What runs for what

Changed Checks (standard scope)
any PHP file php -l, Pint (only fixers new to this change fail the run)
app code, factories, seeders, migrations PHPStan/Larastan on those files (only errors on changed lines fail the run)
controller, middleware, form request, routes/* route:list in a fresh process, then every route('…') / to_route('…') / redirect()->route('…') must name an existing route (the whole project after a routes change)
Blade view, mailable, notification, Livewire, view component the same route-name check on the changed files
config/* config:cache into a temp file (catches closures and unserialisable values)
provider, bootstrap/app.php about (full boot), routes and events probes, then broad scope
event, listener event:list
migration up() + down() inside DB::pretend()
*.blade.php compile with the app's Blade compiler, then php -l on the output
*.json, lang/*.json JSON validity
composer.json composer validate, then broad scope
tests/**/*Test.php runs itself, plus a test-integrity check against the base ref
tests/TestCase.php, tests/Pest.php, fixtures the nearest test directory, or the whole suite
any source file tests reachable within 4 graph hops, plus tests whose name contains the class name

Above max_test_targets (25) related test files, the whole suite runs once instead.

Output for agents

When stdout is not a terminal, which is how agents run commands, the output is NDJSON: one event per line, results streamed as each check finishes, and the verdict always last.

Event kinds, in order: summary, file, impact, expansion, warning, target, then result and its violation lines, then restart, next and verdict. A violation carries path, line, rule, message, severity and, when available, a tip with the command that fixes it.

--json prints one envelope (schema semitexa.laravel-ai-verify/v1) with the same data plus files, targets, results, violations, counts and unchecked_files. --human forces the terminal view.

Verdict rules

  1. No checks ran → incomplete.
  2. Any check failed → fail.
  3. A required check could not finish (timeout, crash, tool missing) → incomplete.
  4. Every check was skipped → skipped.
  5. Otherwise → pass. If no content-reading check reached a result on any changed file (for example, only a README changed), pass is downgraded to incomplete.

Files that no check read are always listed in unchecked_files and in the headline.

Receipts: "verified" you can check

Each ai:verify run writes a receipt. A receipt records:

The commit trailer

With php artisan ai:verify:install --git-hook, a prepare-commit-msg hook stamps every commit that a passing receipt covers exactly:

In CI

Message vs diff

A receipt proves the checks passed. It does not prove the change is the one the commit message describes. While we tested the GitHub Action, Claude Code committed Limit contact name to 250 chars in our test app. Its edit replaced max:255 with max:250, but the name limit was 200, so it changed the email rule. Tests passed, the trailer was earned, and the claim was false.

So the hook and --range also read each commit's subject against its diff:

GitHub Action

This repository is also a GitHub Action that runs both checks on every pull request:

Input Default
mode both receipts, verify, or both
require ai Which commits must carry a valid trailer: ai (co-authored by an AI agent), all, or none (report only)
claims warn Commit message vs diff: warn, fail, or off (needs the package 0.5 or newer)
scope standard ai:verify scope for the re-run
base PR base Commit to compare against
working-directory . Where artisan lives

Outputs: receipts (ok / failed / skipped) and verdict (pass / fail / incomplete / error / not-run). Each violation becomes an annotation on the PR diff, and the job summary gets one table with both checks.

What a receipt is and isn't. The digest catches an edited receipt, not a forged one: whoever can write storage/ can rewrite both. What a receipt adds is that "verified" names something specific. It can be checked against a commit, inspected, and re-run, and CI re-runs it anyway.

ai:graph: a code graph of your Laravel app, for agents

The same graph that selects tests is available directly:

The graph has two layers:

Edges point from the thing that depends to the thing it depends on, so "what does this change affect" is a walk backwards along them.

Safety

Configuration

How it relates to other tools

Tool What it does How this package uses it
Laravel Boost Gives agents docs, schema and logs through MCP, plus guidelines Complementary. This package ships a Boost guideline and skill, so boost:install teaches agents to verify.
Pest / PHPUnit Run tests Used as the runner. Results are read from JUnit XML.
Pest --tia Coverage-based test selection A different trade-off: the graph needs no coverage driver and no baseline.
laravel/pao Compresses tool output for agents Bypassed for child processes, so the structured reports stay parseable.
Larastan, Pint Static analysis and code style Run on the changed files only. Only problems introduced by the change fail the run.

FAQ

How do I stop Claude Code (or Cursor, Codex) from saying "done" when the tests fail?

Rules in CLAUDE.md or AGENTS.md help, but agents don't always follow them. Run php artisan ai:verify:install --hook. The rules go into the instruction files, and Claude Code gets a Stop hook: when the agent tries to finish, ai:verify checks the uncommitted work, and on fail Claude is sent back with the violations. Other agents get the same rules and the same command to run.

How do I stop an AI agent from deleting, skipping or weakening tests to make them pass?

Agents sometimes make a red suite green by editing the tests instead of the code. Researchers call this "reward hacking". Every changed test file is compared with the base ref. The run fails when it loses tests or assertions, or gains skip(), todo(), only() or markTestSkipped. Commenting out an assertion counts as removing it. If a test change is genuinely intended, the agent has to say so explicitly with // verify:accept-test-change <reason>, which shows up in review.

What should go in AGENTS.md / CLAUDE.md for a Laravel project?

At minimum, the agent needs to know how to verify its work and what not to do to pass. See the guideline this package installs. Run php artisan ai:verify:install and it is written into AGENTS.md and CLAUDE.md, and into GEMINI.md, Copilot, Junie, Cursor and Windsurf files if you use them, as an idempotent block next to your own rules and Laravel Boost's.

How do I run only the tests affected by a change in Laravel?

php artisan ai:verify --git-ref=main (or php artisan ai:graph --impact=app/Models/Post.php to just list them). Tests are selected through a project graph: tests that reference a changed class, request a route its controller handles, render a view it touches, or use its factory. It needs no coverage driver and no recorded baseline, unlike coverage-based test impact analysis.

How do I give an AI agent a map of my Laravel codebase?

php artisan ai:graph builds a code graph from your app. It reads the code statically, and it asks the booted app for routes, listeners, model tables and policies. Agents call it with --json (the default when output isn't a terminal):

It gives the agent the same picture a senior Laravel developer has in their head, so it doesn't have to grep and guess, especially around implicit wiring like route-model binding, event listeners and policies.

What will this change break? (impact analysis for Laravel)

php artisan ai:graph --impact=app/Models/Post.php walks the graph backwards from the file. It reports dependent classes, affected routes and the tests that cover them, with a low/medium/high blast-radius band. ai:verify --impact adds the same report to a verification run, and ai:verify uses the graph anyway to pick which tests to run.

Does it replace AI code review?

No. It checks things a reviewer shouldn't have to: the code parses, the views compile, the app boots, migrations run, static analysis and style are clean on the changed lines, the related tests pass, and the tests weren't tampered with. Review time then goes on design and intent, and "it doesn't even run" is off the table.

How do I catch an AI commit that says one thing and changes another?

Install the git hook (php artisan ai:verify:install --git-hook). When a commit subject names a field or method whose line stayed the same while a line just like it changed, the hook warns the agent before the commit exists, and CI annotates the line. See Message vs diff.

Larastan and Pint fail on my legacy code. Will the agent drown in errors?

No. Only problems on the lines this change touched fail the run. PHPStan errors elsewhere in the touched files, and Pint fixers the file already needed, are reported as pre-existing warnings.

Does it work with Laravel Boost, Pest 4/5, PHPUnit, Octane, Horizon?

Yes. It ships a Boost guideline and skill. It runs Pest or PHPUnit and reads their JUnit output. After a change it tells the agent when to run queue:restart, horizon:terminate or octane:reload.

Where it comes from

Semitexa is a modular PHP framework with a Swoole-first runtime, designed so that an AI coding agent can work on a codebase safely. It has a project graph to ask "what does this change affect" instead of grepping, and ai:verify, which checks every change and records what it checked.

This package ports that verification loop to Laravel: the same change classification, scoped planning, coverage gap, test-integrity guard and verdict contract, mapped onto Laravel's conventions and tooling. If you like this way of working, have a look at how far it goes when a framework is designed around it: semitexa.com.

Contributing

Issues and pull requests are welcome at github.com/semitexa/laravel-ai-verify.

License

MIT. See LICENSE.


All versions of laravel-ai-verify with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
illuminate/console Version ^12.0|^13.0
illuminate/contracts Version ^12.0|^13.0
illuminate/support Version ^12.0|^13.0
symfony/process Version ^7.2|^8.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package semitexa/laravel-ai-verify contains the following files

Loading the files please wait ...