Introducing Laravel PAO: Cleaner Output for AI Agents

Introducing Laravel PAO: Cleaner Output for AI Agents

PHP and Laravel developers run the same feedback loop all day: test, fix, analyze, refactor, and test again. The tools in that loop produce output shaped for human terminals: ANSI colors, dot leaders, and decorated tables. That output is fine when you are reading it, but it becomes noisy when an agent does.

For an agent, that same output can hide the parts that matter: the failing assertion, the file path, the line number, the PHPStan identifier, the Rector diff.

Laravel PAO (PHP agent-optimized output) fixes that. It detects when supported PHP tools are being run by an AI agent, such as Claude Code, Cursor, Devin, Gemini CLI, or others. For testing and analysis tools, Laravel PAO returns compact, structured JSON. For Artisan commands, it cleans decorated console output so agents receive the same information with less noise.

Starting today, new Laravel applications include PAO as a dev dependency by default.

What Changes with Laravel PAO

Take a large PHPUnit test suite. Without Laravel PAO, an agent receives hundreds of characters of progress output before it sees whether the suite passed or failed:

With Laravel PAO, the agent gets this instead:

That difference looks small in an article, but it matters a lot in an agent session. The output stays compact regardless of how many passing tests you have.

Failures become more useful, too. Instead of asking the agent to dig through formatted terminal output, PAO gives it the details it needs to continue working:

The agent knows what failed, where it failed, and what message it needs to reason about next.

PAO Supports the Tools You Already Use

Laravel PAO currently supports PHPUnit, Pest, Paratest, PHPStan, Rector, and Laravel Artisan output.

For PHPUnit, Pest, and Paratest, PAO reports compact results: counts, durations, failures, errors, skipped tests, warnings, notices, and deprecations. Extra useful output, such as coverage or profiling summaries, is cleaned and included without the surrounding terminal noise.

PHPStan output is normalized into JSON that focuses on the total number of errors and the per-file details agents need to fix them:

Rector output is also made easier for agents to act on by preserving the changed files, diffs, and applied rectors in a structured format.

The goal is not to invent a new workflow. It is to make the workflow that Laravel developers already use easier for agents to follow.

Cleaner Artisan Output

For Artisan commands, the result is not JSON. It is the same command output with the decoration stripped away.

Commands such as about, db:show, and migrate:status often include decorated tables, dot leaders, colors, and spacing. Those details make output pleasant for humans, but agents do not need them.

For example, output like this:

Becomes:

Same information, fewer tokens for the agent to process.

Your Terminal Stays the Same

This part is important: Laravel PAO does not change the terminal experience for you or your team.

When you run phpunit, pest, phpstan, rector, or artisan directly in your terminal, the output stays the same. PAO only activates when an agent is detected. That gives Laravel better defaults for AI-assisted development without worsening the human workflow.

How PAO Works Under the Hood

Laravel PAO does not introduce a new binary or ask you to run a different command. It starts through Composer's file autoload, which lets it run early in the PHP process:

That autoload file exits immediately unless the current process is running inside an agent environment:

From there, PAO looks at the command being executed and selects the matching driver:

For test runners, PAO avoids scraping terminal output. PHPUnit, Paratest, and Pest already have the real result internally. For PHPUnit, PAO injects PHPUnit's --no-output option. For Pest and Paratest, PAO silences the progress output and lets the runner execute normally.

At shutdown, PAO captures the test result directly from PHPUnit's result facade and builds the JSON from the actual result data:

For Paratest, PAO uses a wrapper runner so parallel worker results can be merged before the final response is written.

From there, PAO extracts the fields agents care about:

That gives PAO the real counts, assertions, duration, failures, errors, warnings, deprecations, and file locations without trying to reverse-engineer formatted text.

For PHPStan and Rector, PAO leans on the tools' own JSON modes instead of parsing their human output:

PAO then normalizes those responses into the fields agents need most. PHPStan error details are also capped by default, with a hint to pass -v when the full list is needed.

At the end of a test, analysis, or refactoring command, PAO writes a single JSON object to standard output. Any extra useful output, such as coverage or profiling information, is cleaned and included without the surrounding terminal decoration.

Artisan takes a different path. In Laravel applications, PAO's service provider is auto-discovered. When an agent is detected, it binds Laravel's console OutputStyle to PAO's implementation and disables Symfony Console decoration as commands start:

Your Artisan commands continue to use the same console APIs, while PAO cleans the output at the boundary.

Available by Default to Provide Better Defaults for AI Agents

New Laravel applications now include Laravel PAO automatically, so there is no configuration file to publish and no setup required.

If you want to add PAO to an existing Laravel application or standalone PHP project, install it with Composer:

PAO works with Laravel 12 and above and PHP 8.3 and above, and can also be used in non-Laravel PHP projects that use supported tools through Composer's autoloader.

Laravel has always cared about the details that make development feel smooth: clear error pages, expressive console output, thoughtful defaults, and tools that help you stay in flow.

As agents become part of that workflow, they need the same kind of care. Laravel PAO keeps the terminal beautiful for humans and makes command output easier for agents to understand, summarize, and act on.

You can learn more about Laravel PAO on GitHub.

Keep reading