Design & Development14 min read

What's New in Laravel — August 2026: Read-Through Filesystems, Agent Observability & MCP's Sprint to 1.0

Ritesh PatelBy Ritesh Patel|September 1, 2026

The July roundup signed off with three watches running: the AI SDK's road to 1.0, the first Laravel 14 signals, and the real-world Pest 5 adoption reports. All three moved in August. Exactly one of them moved the way anyone predicted — and the biggest feature of the month wasn't on any watchlist at all.

Here's the memory August dredged up for us. A few years back we migrated the media library of a large learning platform — course videos, SCORM packages, about a decade of learner uploads spread across a few terabytes — from one object store to another. The runbook was six weeks long: a dual-write phase, nightly sync scripts, a spreadsheet tracking which prefixes had moved, and a Sunday-morning cutover window we rehearsed twice. Nothing about it was hard, exactly. It was just endless, careful, boring risk. In August, Laravel turned that entire runbook into four lines of config.

That's the shape of the month. July was about building things — a first-party image API, agents that ask permission. August was about running things: migrating storage without downtime, watching what your agents actually did, freezing every queue with one command. Call it the operations month.

In This Article

The short version — if you only read one section:

  • Object storage migrations became a config block. The new read-through filesystem driver (v13.26) stacks a primary and fallback disk: writes go to the new store, missing reads fall back to the old one and promote the file forward. Your own traffic performs the migration.
  • Agent runs are fully observable. AI SDK v0.11 threads one invocation ID through every step and tool call and reports it all as plain Laravel events — durations, failures, and sub-agents linked to their parents.
  • laravel/mcp will hit 1.0 before laravel/ai does. The v1.0.0-beta.1 tag landed August 14 with a breaking modernization to the newest MCP protocol revision. Nobody had that milestone order on their card.
  • Queues got serious operational controls. A global pause switch (queue:pause --all), Queue::forward() for remapping queues per environment, and debounceable queued listeners — plus Managed Queues went GA on Laravel Cloud with sub-second worker wake.
  • The one thing worth doing this week: wire a listener to the AI SDK's new ToolFailed event and ship it to your logs. It's ten minutes of work, and the first time an agent misbehaves in production you'll know which run, which tool, and how long it burned before failing.

Your Filesystem Can Migrate Itself Now

Every storage migration has the same awkward middle: new uploads should land on the destination immediately, but millions of existing objects are still sitting on the source, and your application has to read from both stores without knowing which one holds any given file. Teams solve it with dual-write phases, sync scripts, and cutover windows — we've built that scaffolding more times than we'd like to admit.

As of v13.26 (August 18), the framework solves it with a driver. A read-through disk is two ordinary Laravel disks stacked behind one filesystem API:

PHP
1'assets' => [
2    'driver' => 'read-through',
3    'primary' => 'r2',
4    'fallback' => 'legacy-s3',
5],

Writes, listings, and new uploads all go to r2. A read checks r2 first; on a miss it reads legacy-s3, copies the file to r2 — the driver calls this a promotion — and returns the contents. The next request for that file never touches the old store. Point your default disk at the composite and your live traffic starts migrating the working set for you, hottest files first, while you drain the cold tail with background jobs (or Cloudflare's Super Slurper, which the official write-up recommends for exactly that).

The engineering care in the details is what sold us. Before promoting, the driver re-checks the primary in case a concurrent request already copied the file, so racing reads don't clobber each other. Deletes remove the path from the fallback first, then the primary — which prevents the "ghost delete" where you remove a file and a later read cheerfully resurrects it from the old bucket. Streamed reads buffer through php://temp instead of materializing a multi-gigabyte video as a PHP string. And promotion is best-effort by default — a failed copy still serves the file from the fallback — with a throw_on_promotion_failure flag when you'd rather fail loudly.

One gotcha worth knowing before you rely on it: Storage::url() resolves against whichever disk currently holds the file, and the browser then fetches directly from that provider. Files served by public URL never pass through your application, so they never promote. If most of your delivery is direct-URL — a CDN-fronted media library, say — application traffic will migrate less than you'd hope, and the background bulk copy does the real work.

In practice: this is the feature we'd have used on that learning-platform migration, and it's the one we'll use on the next one. The dual-write code, the sync-state spreadsheet, the rehearsed cutover — all replaced by a config block, a queue of copy jobs for the cold tail, and a verification pass before retiring the old credentials. It also composes in less obvious ways: primary and fallback can be scoped disks with different prefixes in the same bucket, which turns "reorganize ten years of upload paths" — a project every long-lived app postpones indefinitely — into the same promote-on-read pattern.

Tip
The counter-intuitive part: this is the second month running that Laravel absorbed an infrastructure playbook rather than a library. July turned image processing into a driver; August did it to the storage-migration runbook. The read-through pattern itself is ancient — it's cache-aside, applied to durable storage. What's new is that it lives behind the filesystem contract, so the eleven-step migration plan becomes invisible to every line of application code you've already written.

Agents Got a Flight Recorder

July's AI SDK story was control: human-in-the-loop approvals, agents pausing before side effects. August's story is the natural sequel — visibility. Version 0.11.0 (August 19) makes an agent run something you can reconstruct after the fact, and it does it in the most Laravel way imaginable: events.

Every run now carries a single invocation ID from the first prompt to the terminal state. Along the way the SDK dispatches plain Laravel events at each stage — StartingStep and StepCompleted around every model call, InvokingTool and ToolInvoked around every tool execution, StepFailed and ToolFailed when things go wrong, and a terminal failure event when a run dies outright. Tool events carry the arguments, the exception if there was one, and wall time in milliseconds. And when an agent invokes another agent as a tool — the pattern we dug into in our multi-agent systems post — the child run is linked back to its parent, so a nested delegation chain reads as one traceable tree instead of disconnected transcripts.

Because these are ordinary events, the plumbing you already own just works:

PHP
1use Laravel\Ai\Events\ToolFailed;
2
3Event::listen(function (ToolFailed $event) {
4    Log::warning('Agent tool failed', [
5        'invocation' => $event->invocationId,
6        'tool' => $event->tool->name(),
7        'exception' => $event->exception->getMessage(),
8        'ms' => $event->time,
9    ]);
10});

Send that to your log channel, your metrics pipeline, Nightwatch, a database table for an audit UI — it's a listener, so it goes wherever your listeners already go. Laravel News ran four separate articles on this release inside a single week, which tells you how much the community had been waiting for exactly this.

The same release quietly fixed the failure modes that hurt most in production. Failover now triggers on provider connection failures, on Anthropic usage-limit rejections, and on transient gateway errors — not just clean 503s. Streaming errors now throw instead of silently ending the run, which previously produced the worst kind of bug: an agent that appeared to finish but had actually died mid-thought. There's a new hosted ToolSearch tool (OpenAI and Anthropic) that lets an agent discover and load tools on demand instead of carrying its entire toolbox in every prompt. Quick hits: transcription landed for Groq and OpenAI-compatible providers, xAI gained web and file search, OpenRouter gained web fetch, the default Gemini model moved to gemini-3.7-flash, and the test fakes grew an assertPromptedTimes() helper.

In practice: we run agent workloads where "what did it actually do?" is a compliance question, not curiosity. Until now the answer was hand-rolled — wrap every tool, log every step, maintain the plumbing forever. As of 0.11 that plumbing is the SDK's job, and ours reduces to listeners. If you're running agents in production and you wire up nothing else this month, wire up ToolFailed and the terminal-failure event; the first incident will repay the ten minutes a hundred times over.

And no, it's still not 1.0 — v0.11.0 makes it four months of everyone asking. But notice the ordering: approvals in July, observability in August, API freeze later. Instrument the thing before you promise its shape won't change. That's the adult order of operations, and it's the opposite of how most SDKs in this space have shipped.

MCP Is Winning the Race to 1.0

While everyone watched laravel/ai for a 1.0 signal, a different package walked past it. laravel/mcp tagged v1.0.0-beta.1 on August 14 — and it's a real modernization, not a ceremony. The beta serves only the MCP 2026-07-28 protocol revision, drops the legacy initialize handshake entirely, goes stateless on HTTP transports, adds caching hints to cacheable results, and advertises MCP Apps through the extensions capability. There's a published 1.0 upgrade guide, and the 0.x line kept shipping releases during the beta — v0.9.4 actually landed two days after beta.1 — so nobody's production server is stranded mid-transition.

The stateless move is the one with teeth. Session state was the awkward part of hosting MCP servers behind load balancers; removing it makes an MCP endpoint as boring to scale as any other Laravel route. Boring to scale is the highest compliment infrastructure can earn.

The tooling layer above MCP kept pace. Laravel Boost went from v2.5 to v2.7 across August, and the official Laravel blog closed the month (August 31) with a genuinely useful pattern: an agent skill that reads an existing codebase, finds the conventions you actually follow, and records them as scoped rules for AI tools — extracting your house style instead of asking you to write it down from memory. Meanwhile the community shipped agents that consume all of this: Laravel Auditor points an AI agent at your app for auditing, and Laravel Tackle runs a coding agent inside your Laravel app.

In practice: if you shipped an MCP server on 0.x — we've built them for internal tooling, and our chatbot work increasingly assumes MCP as the integration surface — the upgrade guide is your September task. The changes are breaking but mechanical, and being on the final protocol revision before 1.0 lands means doing the migration once instead of twice.

Warning
Don't misread the milestone order. MCP reaching 1.0 first isn't a signal that the AI SDK is stalling — it's a signal about surface area. An MCP server implements a published protocol with a fixed shape; an agent SDK is still discovering what its abstractions should be, in public, while the underlying model capabilities shift monthly. The package with the smaller API contract freezes first. That's exactly the order you should want.

Queues Grew a Big Red Pause Button

Queue work has quietly been the framework's most consistent thread all year, and August was its best month yet — three genuinely new operational controls in the framework, and the Cloud side went GA.

The global pause switch (v13.25) fixes a gap that anyone who's done an emergency deploy has felt: you could pause the scheduler outright, but pausing queues meant maintenance mode or a script that looped over every queue on every connection — and queue names drift with every feature release. Now it's one command:

Terminal
1php artisan queue:pause --all

Every queue on every connection stops processing; queue:resume --all brings it back, and QueuesPaused / QueuesResumed events fire for your alerting. The design detail we appreciate: global and per-queue pause are independent switches, so resuming everything after a deploy won't reactivate the one queue you'd deliberately stopped last Tuesday. In practice: this slots straight into deploy scripts — freeze side effects, migrate, resume — and into incident response, where "stop everything touching the payment provider, now" was previously a scramble and is now a single command you can give anyone on the team.

Queue::forward() (v13.26) solves the environment-drift problem from the other side. When staging runs Redis, production runs SQS, and one environment is piloting Cloud's managed queues, the routing logic ends up smeared across job constructors and dispatch calls. Forwarding centralizes it in one provider:

PHP
1Queue::forward('reports', 'reports.fifo', 'cloud');
2Queue::forward('payments', connection: 'cloud');
3Queue::forward('updates', 'notifications');

Rename a queue, move it to another connection, or both — with zero changes at any dispatch site. In practice: this is the migration tool for adopting managed queues gradually. Move one heavy queue to Cloud, watch it for a week, move the next. Every gate lives in one file that's easy to review and easy to revert.

Debounceable queued listeners (v13.26) extend the #[DebounceFor] attribute from jobs to event listeners:

PHP
1use Illuminate\Contracts\Queue\ShouldQueue;
2use Illuminate\Queue\Attributes\DebounceFor;
3
4#[DebounceFor(30, maxWait: 120)]
5class UpdateProductSearchIndex implements ShouldQueue
6{
7    public function debounceId(ProductUpdated $event): string
8    {
9        return (string) $event->product->getKey();
10    }
11
12    public function handle(ProductUpdated $event): void
13    {
14        // Reindex the product...
15    }
16}

Fifty rapid edits to the same product produce one reindex, thirty seconds after the last edit, with maxWait guaranteeing it runs within two minutes even under a continuous stream. Different products debounce independently. One sharp edge to respect: debouncing is last-dispatch-wins while ShouldBeUnique is first-dispatch-wins, so a listener can't be both — the framework will tell you no. In practice: search indexing, cache warming, webhook fan-out — every "expensive thing triggered by chatty events" in our codebases currently does this dance with hand-rolled cache locks. This deletes those locks.

On the Cloud side, Managed Queues went GA on August 6, and the launch post is worth reading for the engineering honesty alone. The rebuild puts every worker in its own isolated pod (so one out-of-memory job can't take down its neighbors), reads queue depth directly from SQS instead of through your application, and scales on queue pressure and average job runtime — because five queued jobs sounds trivial until each one takes two minutes. The headline fix: idle workers now sleep instead of shutting down and wake in under a second when a job arrives, thirty times faster than the old pod cold start. Scale-to-zero stopped being a trade-off. Add FIFO queues for exactly-once ordered delivery, minimum worker floors for latency-critical queues, cron-based scaling windows for predictable spikes, and bulk retry for failed jobs, and the framework's Queue::forward() suddenly looks less like a convenience and more like the on-ramp.

The Sharp-Edges Month: Security and the Data Layer

The v13.27 release (August 25) carried an unusually deliberate security sweep, and it's worth pausing on because none of it was reactive — this was hardening before the exploit writeups, mostly from one contributor methodically auditing input handling. Loose-comparison bypasses were closed in the in and in_array validation rules (where "1e2" and "100" could previously satisfy an equality they shouldn't), literal asterisks and dots in input keys stopped being confused with wildcards during request merging, and the maintenance-mode bypass cookie now guards against a non-string MAC. Alongside those: query-binding masking for exception messages, so a failed query in your error tracker no longer prints the email address or token that was bound to it.

The data layer got sharper in the useful, unglamorous ways. whereBinary() (v13.27) makes case-sensitive MySQL comparisons a first-class query method instead of a raw BINARY expression. refreshForUpdate() (v13.27) re-reads a model with a pessimistic lock — the missing half of every optimistic "read, check, write" flow that occasionally loses a race. And v13.29 (August 25) taught MariaDB vector distance queries to work correctly and added an AsVector Eloquent cast — small lines in a changelog, but together they mean vector search in Laravel is no longer a Postgres-only conversation. For teams on MariaDB-heavy stacks (a lot of the Moodle LMS hosting world, for one) that's the difference between "add pgvector infrastructure" and "add a cast."

July's headline feature spent August maturing in public, which is exactly what you want to see from a one-month-old component: the Image API gained HEIC decoding and broader AVIF support, dominant-color detection, an Image::fromStream() constructor, and it now implements Responsable — return an image straight from a controller. A driver-based component absorbing a month of community PRs without breaking its API is the design vindicating itself.

And the steady accumulation: modelKeys() on the Eloquent builder, an array_keys validation rule, foreignUlidFor() in migrations, closure support in wherePivot(), process-fake assertion helpers and iterable process pools, Guzzle 8 support, Postgres keepalive DSN options, and a fix for validation stalling for minutes on very large arrays — the kind of fix you only notice when a CSV import that used to hang suddenly doesn't. New queue introspection events (JobReleased, UniqueJobSkipped, JobTimedOut now carrying its timeout, NotificationSkipped) round out the observability theme from the other direction.

In practice, the two to act on this week: turn on query-binding masking thinking wherever your error tracker retains history — it converts a compliance finding into a config change — and if any of your uniqueness or lock-sensitive flows read-then-write, audit them against refreshForUpdate(). Both are under an hour of work.

What This Means for Teams Shipping Laravel

Time to settle July's scorecard honestly.

July's teaseWhat August actually delivered
AI SDK 1.0 "inching closer"v0.11 — not 1.0, but full run observability, which is worth more than a version number
First Laravel 14 signalsNative QUERY routing has landed on the framework's master branch — Route::query() is real, waiting for 14
Pest 5 adoption reports5.0.3 to 5.1.3 in one month; PHPUnit 13.3 under the hood; TIA fixes for Livewire single-file components and the mutation plugin — the friction log of real adoption, in public

That master-branch detail deserves a sentence: we checked on September 1, and the QUERY verb now sits in the router's verb list on master with a first-class Route::query() registrar — the routing half of the feature that shipped client-side in July. Master is the branch that becomes Laravel 14. Still no date, still no 14.x branch, but the signals are accumulating exactly where you'd expect them to.

Three threads from August worth carrying into your planning:

The framework keeps absorbing infrastructure playbooks. Images in July, storage migration in August. The pattern to internalize: before you architect the next piece of operational scaffolding — a migration plan, a media pipeline, a queue-routing layer — check whether the framework just made it a driver. The answer has been "yes" two months running, and the checks are cheaper than the scaffolding.

The agent stack is becoming legible, and legibility is the adoption unlock. Approvals, then observability, then a protocol frozen at 1.0, then tools that extract your conventions into rules. None of this makes agents more capable; all of it makes them auditable — and auditable is what the enterprise conversations we're in actually stall on. The teams wiring up run observability now are the ones who'll pass those reviews later.

Ops primitives are compounding across the framework-Cloud boundary. Global pause, forwarding, and debouncing in the framework; sub-second wake, pressure-based autoscaling, and FIFO delivery on Cloud — each side making the other more usable. You don't have to be a Cloud customer to benefit; the framework pieces stand alone. But the seam between them is visibly where Laravel is investing.

September's watchlist writes itself: the MCP 1.0 final, month four of the AI SDK 1.0 vigil, the State of Laravel 2026 survey results (it opened August 26 — go fill it in), the Vite+ rollout through the starter kits, and whatever the master branch does next as Laravel 14 season approaches. We'll cover all of it in the September roundup.

Tip
Need a Laravel team that ships against the latest framework features instead of waiting six months to adopt them? We've been building Laravel applications for over 11 years — SaaS platforms, AI products, e-learning systems on Moodle LMS, and queue-heavy workloads running at scale. Get a free quote or schedule a call with our Laravel team.

Related reading

Frequently Asked Questions

What is Laravel's read-through filesystem driver?
Shipped in v13.26 on August 18, 2026, the read-through driver stacks two ordinary Laravel disks — a primary and a fallback — behind one filesystem API. Writes and listings go to the primary; a read that misses the primary falls back to the old disk and, by default, copies the file forward so the next read is local. That turns an object storage migration (S3 to R2, local to cloud, even prefix to prefix inside one bucket) into a config block instead of a rewrite: new uploads land on the destination immediately, and your traffic migrates the active files for you. Deletes remove the path from both disks so a removed file can't be resurrected by a later promotion, and a strict mode (throw_on_promotion_failure) is available when you'd rather fail a read than serve a file that couldn't be copied.
What's new in Laravel AI SDK 0.11?
Version 0.11.0 (August 19, 2026) is the observability release. Every agent run now carries a single invocation ID from first prompt to final answer, and the SDK dispatches ordinary Laravel events at each stage — StartingStep, StepCompleted, StepFailed, ToolInvoked, ToolFailed with wall time in milliseconds, and a terminal failure event — with sub-agents linked back to their parent run. It also adds a hosted ToolSearch tool for loading tools on demand (OpenAI and Anthropic), meaningfully smarter failover (provider connection failures, Anthropic usage-limit rejections, and transient gateway errors now fail over instead of erroring), and streaming errors that throw instead of silently ending the run. It is still not 1.0 — that watch enters its fourth month.
How do I pause all Laravel queues at once?
As of Laravel v13.25 (August 11, 2026), php artisan queue:pause --all pauses job processing on every queue across every connection, and queue:resume --all brings it all back — no maintenance mode, no looping over queue names, no per-connection scripting. The pause survives across your worker fleet and fires QueuesPaused and QueuesResumed events you can hook for alerting. Global and per-queue pause are deliberately independent switches: if you paused one queue individually before pausing everything, resuming all leaves that queue paused, so a deploy-wide freeze can't accidentally reactivate something you'd stopped on purpose. The command pairs naturally with deployments and incident response, where stopping side effects quickly matters more than anything else in the moment.
Is Laravel MCP 1.0 released?
Not final yet — laravel/mcp tagged v1.0.0-beta.1 on August 14, 2026, and it's a genuinely breaking modernization rather than a version-number ceremony. The beta serves only the MCP 2026-07-28 protocol revision, drops the legacy initialize handshake, goes fully stateless on HTTP transports, adds caching hints to cacheable results, and advertises MCP Apps through the extensions capability. There's a published 1.0 upgrade guide, and the 0.x line kept receiving releases during the beta, so existing servers aren't stranded. The notable part is the milestone order: the ecosystem has spent months watching laravel/ai for a 1.0 signal, and the MCP server package is going to cross that line first.

Ready to start your project?

Tell us about your requirements and we'll get back with a clear plan within 24 hours. No sales pitch — just an honest conversation.

Ritesh Patel
About the Author
Ritesh Patel
Co-Founder & CTO, Treesha Infotech

Co-founded Treesha Infotech and leads all technology decisions across the company. Full-stack architect with deep expertise in Laravel, Next.js, AI integrations, cloud infrastructure, and SaaS platform development. Ritesh drives engineering standards, code quality, and product innovation across every project the team delivers.

Let's Work Together

Ready to build something
remarkable?

Tell us about your project — we'll get back with a clear plan and honest quote.

Free Consultation
No Commitment
Reply in 24 Hours
WhatsApp Us