NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Packagist · #2400 most downloaded on Packagist
Psalm plugin for Laravel
Last release 2 days ago
05 Oct 2026
Ships fairly regularly
a new release about every 9 days
Some releases are documented
notes for 25 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
8 years old
192 releases · first in 2019
…the plugin when a vendor file raised a load-time deprecation
Two opt-in rules that catch typos in route names and filesystem disks, plus sharper inference for Eloquent relations, aggregate attributes, when()/unless() callbacks, and Collection::filter(). How to enable them in your psalm.xml:
<pluginClass class="Psalm\LaravelPlugin\Plugin">
<findMissingViews value="true" />
<findUnregisteredRouteNames value="true" />
</pluginClass>or enable experimental features:
<pluginClass class="Psalm\LaravelPlugin\Plugin">
<experimental value="true" />
</pluginClass>UnregisteredRouteName rule for route names missing from the booted app's route table: route(), to_route(), URL::route()/signedRoute()/temporarySignedRoute(), Redirect::route(), redirect()->route(), url()->route(). Enable with <findUnregisteredRouteNames value="true" /> or <experimental value="true" /> (#1573) return redirect()->route('users.shwo', $user);
+// UnregisteredRouteName: Route name 'users.shwo' is not registeredUnconfiguredFilesystemDisk rule for Storage::disk() names absent from filesystems.disks, with a closest-name suggestion. Enable with <findUnconfiguredFilesystemDisks value="true" /> or <experimental value="true" />. \Storage::disk() now also narrows to FilesystemAdapter like the facade (#1571) Storage::disk('publik')->put($path, $contents);
+// UnconfiguredFilesystemDisk: Disk 'publik' is not configured in filesystems.disks, did you mean 'public'?when()/unless() callback parameters from the condition value: when() passes the truthy value, unless() the falsy one, and a Closure condition passes its return type (#1645) /** @var ?int $limit */
$query->when($limit, function (Builder $q, string $limit) { /* ... */ });
-// no issue: the callback parameter was never checked
+// InvalidArgument: when expects callable(Builder<...>, int):mixed|null, but Closure(Builder, string):void providedreturn $this->allRevisions()->where(...)) (#1646) // HasPaymentSlips trait: public function paymentSlips(): MorphMany { return $this->morphMany(PaymentSlip::class, 'owner'); }
$member->paymentSlips();
-// MorphMany<Model, Model>
+// MorphMany<PaymentSlip, Member>Collection::filter(callable) like where(callable), and recognize is_subclass_of(), is_a(), is_scalar(), is_iterable(), is_resource() and null checks (!is_null($x), $x !== null) in both (#1651) $items->filter(fn (Countable $x): bool => $x instanceof Stringable);
-// Collection<int, Countable>
+// Collection<int, Countable&Stringable>
$classes->filter(fn (string $c): bool => is_subclass_of($c, Job::class));
-// Collection<int, string>
+// Collection<int, class-string<Job>>{relation}_count / {relation}_exists as nullable unless withCount()/withExists()/loadCount()/loadExists() is proven on that model (or the relation is in $withCount), and type withMin/withMax/withSum/withAvg attributes from the related column's type (#1628) $post->comments_count ?? $post->loadCount('comments')->comments_count;
-// RedundantCondition: comments_count was always int
+// no issue: int|null until a count is proven loadedModel as @psalm-consistent-constructor, so new $class() on a class-string<Model> is no longer UnsafeInstantiation. A model overriding __construct with an incompatible signature is now reported, since Eloquent's own new static($attributes) already breaks on it (#1626) /** @param class-string<Model> $class */
function make(string $class): Model { return new $class(); }
-// UnsafeInstantiation
+// no issueCollection in BelongsToMany::sync(), syncWithoutDetaching(), syncWithPivotValues() and their Laravel 13 *OrFail() variants (#1644) $user->roles()->sync($roles->pluck('id'));
-// InvalidArgument / ImplicitToStringCast
+// no issue$this as the declaring model for relation calls inside non-final models, so return $this->rel()->where(...) no longer reports MoreSpecificReturnType / LessSpecificReturnStatement (#1629, #1632)SoftDeletes methods per receiver model on a generic custom builder shared by a parent and child model, instead of whichever model was scanned last (#1638)@psalm-mutation-free from Request::input(), which lazily decodes JSON: a FormRequest overriding input() is no longer flagged (#1627)$request->input(...), Artisan::command(...), Job::dispatch(...)) with zend.assertions=1 (#1659)Full Changelog: v4.16.6...v4.17.0
One column per quarter.
v4.16.6 restores vendor methods on stubbed Laravel classes that silently resolved to mixed , and tightens docblock types for console, events, facades,
v4.16.6 restores vendor methods on stubbed Laravel classes that silently resolved to mixed, and tightens docblock types for console, events, facades, mail, and relations.
mixed when nothing in the project named that class before the plugin's stubs loaded. Psalm then skipped the class's vendor file, so with __call (Macroable) every method the stub did not declare became mixed with no issue reported. Affected classes included Events\Dispatcher, Http\Client\PendingRequest, Http\Client\Response, FormRequest, Pipeline, and several facades (#1616, #1618) app('events')->hasListeners('order.shipped');
-// mixed
+// boolArtisan::all() and Console\Kernel::all() (contract and concrete) as array<array-key, Command> instead of array (#1612) $commands = Artisan::all();
-// array<array-key, mixed>
+// array<array-key, Symfony\Component\Console\Command\Command>DB::getQueryLog() entries and Schema::getColumnListing() with the shapes Connection and Schema\Builder already document, instead of the facades' plain array (#1612) $log = DB::getQueryLog();
-// array<array-key, mixed>
+// list<array{query: string, bindings: array<array-key, mixed>, time: float|null, readWriteType?: string|null}>until(), dispatch() with $halt = true) on Events\Dispatcher, its contract, and the Event facade as mixed: it returns the first non-null listener response, not array|null (#1612)MailMessage properties ($view nullable; $from, $replyTo, $attachments, $rawAttachments with the shapes MailChannel accepts), MailMessage::render() as HtmlString|string, and Notification::$id as string|null (#1612)Collection of related models in BelongsToMany::saveMany() and saveManyQuietly(), and keep its type on return (#1612)Reflector::getParameterClassNames() as list<string>, Route::methods() as array<string>, accept null in Migrator::usingConnection(), and mark UrlGenerator's resolver, formatter, and forced root/scheme properties nullable (#1612)Full Changelog: v4.16.5...v4.16.6
v4.16.5 moves the Psalm 7 floor to 7.0.0-beta23 .
v4.16.5 moves the Psalm 7 floor to 7.0.0-beta23.
vimeo/psalm ^7.0.0-beta23 and psalm/psalm-plugin-api ^0.3.0. Psalm 7.0.0-beta23 pins psalm/psalm-plugin-api 0.3.0, so v4.16.4 could not be installed next to it (#1606)ResponseFactory::make() call is no longer hidden by an attachment download elsewhere in the project (#1606, via vimeo/psalm#12037)Full Changelog: v4.16.4...v4.16.5
v4.16.4 moves the Psalm 7 floor to 7.0.0-beta22 , adds a header-injection sink for response headers, and fixes facade and Pipeline inference gaps.
v4.16.4 moves the Psalm 7 floor to 7.0.0-beta22, adds a header-injection sink for response headers, and fixes facade and Pipeline inference gaps.
vimeo/psalm ^7.0.0-beta22 and psalm/psalm-plugin-api ^0.2.0. Psalm 7.0.0-beta21 renamed the internal taint node factory, so older betas no longer work with this release (#1455, #1456, #1587)TaintedHeader: the $headers argument of ResponseFactory::make() (direct, contract, and facade forms), the three-argument response() helper, and new Response() is now a header sink. The attachment exemption still applies only to the TaintedHtml content finding (#1575) $title = $request->input('team');
return response()->make($csv, 200, [
'Content-Disposition' => "attachment; filename=\"{$title}.csv\"",
]);
-// before: no issue
+// now: TaintedHeader: Detected tainted headeralies-dev/psalm-plugin-pest instead of psalm/plugin-phpunit in psalm-laravel init when the project requires pestphp/pest (#1596)App::environment() to bool when called with environment names and to string without arguments, instead of the facade's unconditional string|bool (#1453) $isProd = App::environment(['production', 'staging']);
-// string|bool
+// boolPipeline::through() and Pipeline::pipe(), matching Laravel's Pipeline::carry() (#1590) $pipeline->through(new AuthenticateMiddleware());
-// InvalidArgument: Argument 1 of Pipeline::through expects array<Closure|callable|string>|Closure|callable|string, but AuthenticateMiddleware provided
+// accepted, returns Pipeline&staticFull Changelog: v4.16.1...v4.16.4
v4.16.1 refines the v4.16.0 laravel/ai and MissingView work: exempts annotated prompt guards from TaintedLlmPrompt , extends MissingView to mailables,
v4.16.1 refines the v4.16.0 laravel/ai and MissingView work: exempts annotated prompt guards from TaintedLlmPrompt, extends MissingView to mailables, and fixes a Redis facade regression.
laravel/ai middleware guards annotated with @psalm-taint-escape llm_prompt from TaintedLlmPrompt, so a blocking prompt-injection guard (e.g. promptphp/intercept) silences the finding at its dispatched handle()/__invoke() method (#1441)
final class PromptInjectionGuard
{
/** @psalm-taint-escape llm_prompt */
public function handle(AgentRequest $request, Closure $next) { /* ... */ }
}
// agent's middleware() resolves to [PromptInjectionGuard::class]
// TaintedLlmPrompt no longer fires on prompts passing through itMailables\Content constructors and extend MissingView to Mailable::view()/markdown()/text() and view Factory::composer()/creator() (#1431, #1432)
new Content(view: 'emials.welcome');
-// before: no issue
+// now: MissingView: View 'emials.welcome' not found in any of the registered view pathsRedis::pipeline()/transaction() callback results as list<mixed> instead of reporting UndefinedMagicMethod (#1427)
Redis::pipeline(fn ($pipe) => $pipe->get('key'));
-// before: UndefinedMagicMethod: Magic method Illuminate\Support\Facades\Redis::pipeline does not exist
+// now: list<mixed>handle(), and controller-action return values as framework-consumed, fixing spurious PossiblyUnusedReturnValue under --find-unused-code (#1434)Full Changelog: v4.16.0...v4.16.1
v4.16.0 adds taint-analysis support for the laravel/ai package: prompt-injection detection plus tracking of LLM output into SQL, shell, and HTML sinks
v4.16.0 adds taint-analysis support for the laravel/ai package: prompt-injection detection plus tracking of LLM output into SQL, shell, and HTML sinks. It also extends MissingView to every view-name-bearing API and ships several new type-narrowing features.
The plugin now understands laravel/ai (>=0.11.0 <1.0.0, #937). The integration loads only when Composer reports the package installed; apps without it get no extra stubs or handlers. TaintedLlmPrompt is enabled automatically at its normal error level; <findPromptInjection value="false" /> turns off prompt-input findings while keeping model-output findings.
Untrusted data (request input, HTTP responses, tool arguments, retrieved documents) reaching an LLM prompt is reported:
final class SupportAgent
{
use \Laravel\Ai\Promptable;
}
(new SupportAgent())->prompt($request->input('question'));
// 🔴 TaintedLlmPrompt: Detected tainted LLM promptLLM output is treated as a taint source, so it is followed into the existing SQL, shell, file, and HTML sinks:
function run(\Laravel\Ai\Responses\AgentResponse $response): void {
DB::select($response->text);
}
// 🔴 TaintedSql: raw model output interpolated into a queryMissingView beyond view() and Factory::make() to Factory::first()/renderWhen()/renderEach(), response()->view(), Route::view(), MailMessage::view()/markdown(), and assertViewIs() (#1407)
Route::view('/welcome', 'welcom');
// 🔴 MissingView: View 'welcom' not found in any of the registered view pathsArr::get() value type from known array shapes, including dot-notation keys and $default handling (#1402)
/** @param array{a: int} $data */
$value = Arr::get($data, 'a');
-// before: mixed
+// now: intManager::driver() to its create*Driver() return type, including the no-argument default-driver form (#1410)
final class ShippingManager extends Manager
{
public function getDefaultDriver(): string { return 'ups'; }
public function createUpsDriver(): Shipper { return new UpsShipper(); }
}
$manager->driver('ups'); // Shipper
-$manager->driver(); // was: mixed
+$manager->driver(); // now: ShippergetCollection() to a model's custom Eloquent collection (#1408)
#[CollectedBy(WorkOrderCollection::class)]
class WorkOrder extends Model {}
WorkOrder::query()->paginate()->getCollection();
-// before: Eloquent\Collection<int, WorkOrder>
+// now: WorkOrderCollection<int, WorkOrder>TaintedHtml for response()->make() bodies explicitly served as attachments (#1348)
response()->make($csv, 200, ['Content-Disposition' => 'attachment; filename="export.csv"']);
-// before: TaintedHtml
+// now: no issue — the response is a download, not rendered HTMLnew Illuminate\Http\Response(...), and safe literal Content-Type values; HTML, XML, SVG, and script types stay reported (#1417)PersonalAccessToken binding for models using HasApiTokens without an explicit @use annotation, fixing spurious MissingTemplateParam (#1425)HasFactory bindings from newFactory(), static $factory, and #[UseFactory] without suppressing unrelated MissingTemplateParam diagnostics on the model (#1423)handle() methods, Eloquent relations) so --find-unused-code stops flagging them as dead (#1422)Full Changelog: v4.15.7...v4.16.0
Taint accuracy for named arguments, plus three Eloquent and Collection narrowings.
Taint accuracy for named arguments, plus three Eloquent and Collection narrowings.
// sinkNamed(string $path = 'safe', string $label = 'x'), file sink on $path
sinkNamed(label: (string) $request->input('page'));
-// TaintedFile (before): the taint landed on $path, which never saw the request
+// no issue: the argument is attributed to $labelAbstractPaginator::getCollection() and AbstractCursorPaginator::getCollection() to Eloquent\Collection when the paginator holds models (#1397). The 33 methods that exist only on the Eloquent collection (load*, find, fresh, modelKeys, toQuery, ...) are now reachable. $users = User::paginate();
$users->getCollection()->load('posts');
-// UndefinedMethod (before): Support\Collection<int, User> has no load()
+// now resolves: Eloquent\Collection<int, User>select() stubs for Collection, LazyCollection, and Eloquent\Collection (#1399), including the select(null) branch and the variadic form. $rows = collect([['a' => 1, 'b' => 2]])->select('a');
-// Collection<array-key, mixed>&static (before); select('a', 'b') reported TooManyArguments
+// Collection<array-key, array<array-key, mixed>>Auth::guard() and Auth::shouldUse() when the guard name is a string-backed enum case (#1405). Previously any non-literal argument dropped all narrowing back to the bare contract. Auth::guard(Guards::Admin)->user();
-// Illuminate\Contracts\Auth\Guard (before)
+// now resolves through SessionGuard to the configured user model<experimental value="true" /> now also enables findSerializedQueuedModels, unless the project sets that flag explicitly (#1400). experimental is the early-access switch for rules that are off by default and on their way to becoming default.Full Changelog: v4.15.6...v4.15.7
Two new inference sources for Eloquent-backed code, one new opt-in queue-safety rule, and three false-positive fixes across migrations, model attribut
Two new inference sources for Eloquent-backed code, one new opt-in queue-safety rule, and three false-positive fixes across migrations, model attribute helpers, and pipelines.
SerializedQueuedModel rule for ShouldQueue classes that hold an Eloquent model without reaching Illuminate\Queue\SerializesModels, where the whole model is written into the queue payload instead of a ModelIdentifier (#1385). Enable with <findSerializedQueuedModels value="true" />. Detection resolves the flattened __serialize() / __sleep() rather than matching the trait name, so framework bases that already pull the trait in (Illuminate\Foundation\Queue\Queueable, Illuminate\Notifications\Notification) and classes that hand-write their own serialization stay silent. final class ReconcileLedger implements ShouldQueue
{
public function __construct(private Customer $customer) {}
- // silent: the entire Customer row is written into the queue payload
+ // SerializedQueuedModel: $customer will be serialized whole into the queue payload
}Arr::pluck() value and key types from the element model's @property annotations, matching what Collection::pluck() and Builder::pluck() already do (#1383). /** @param list<Customer> $rows */ // Customer has @property string $id
-Arr::pluck($rows, 'id'); // array<array-key, mixed>
+Arr::pluck($rows, 'id'); // list<string>$schema = Schema::connection(...) in migrations, so columns declared through a variable-held builder (#1382).Model::getAppends() and Model::getMutatedAttributes() to list<string>, so callers no longer have to re-assert the element type (#1381).Pipeline::then() from its destination closure instead of leaving it mixed (#1376).Full Changelog: v4.15.5...v4.15.6
Taint precision and Eloquent type narrowing. Two taint fixes remove a duplicate finding and close a missed SQL injection, and four type fixes sharpen
Taint precision and Eloquent type narrowing. Two taint fixes remove a duplicate finding and close a missed SQL injection, and four type fixes sharpen inference on facades, collections, and the query builder.
@method tags, so templated facade methods resolve their real return type (#1370) $value = Cache::remember('key', 60, fn (): User => User::first());
-// mixed — the generated @method tag outranked the plugin's stub
+// UsergroupBy() and keyBy() keys for model columns instead of widening to array-key (#1369) $byId = User::all()->keyBy('id');
-// Collection<array-key, User>
+// Collection<int, User>chunkById() callback like chunk(), so the chunk is a templated collection rather than mixed (#1373) Article::query()->chunkById(100, function ($chunk) { ... });
-// $chunk: mixed
+// $chunk: Collection<int, Article>$fetchUsing argument on DB::select(), DB::selectResultSets(), DB::cursor(), and their Connection counterparts, while keeping the three-argument signature an error on Laravel 12 (#1374) DB::cursor('select * from users', [], true, [PDO::FETCH_ASSOC]);
-// TooManyArguments — the stub declared three parameters
+// accepted on Laravel 13; still TooManyArguments on Laravel 12Row types follow the fetch mode, so a custom $fetchUsing no longer claims stdClass:
$rows = DB::cursor('select 1'); // Generator<int, stdClass>
$assoc = DB::cursor('select 1', [], true, [PDO::FETCH_ASSOC]);
-// Generator<int, stdClass>
+// Generator<int, mixed>TaintedInclude only, not also TaintedFile (#1358). A view name selects which template executes; it cannot reach an arbitrary path, because the view finder rewrites . to / and appends a fixed extensionWhereColumnTaintHandler's removal bridge on the AST node itself rather than spl_object_id, closing a missed SQL injection (#1366). Psalm frees foreign ASTs mid-file, so a reissued object handle could hit a stale record and strip sql taint from an unrelated expressionFull Changelog: v4.15.4...v4.15.5
Extends taint reporting to the call forms Laravel applications actually write — facade statics, response() on its contract, and view() names — and cle
Extends taint reporting to the call forms Laravel applications actually write — facade statics, response() on its contract, and view() names — and clears the false positives that surfaced alongside it.
response() contract methods, and view() names (#1318). A facade's surface is @method pseudo-methods resolved through __callStatic, whose parameters have no docblock to carry a sink, so the static form was silent while the chained form fired. Redirect::to($request->input('next'));
-// silent: the facade pseudo-parameter carried no sink
+// TaintedHeader: Detected tainted header$with and $withCount (#1321). Supports dotted paths, column selectors, and the $withCount alias grammar; defers when an intermediate related model cannot be resolved. class Post extends Model
{
protected $with = ['auther'];
- // silent: eager-load defaults were never validated
+ // UndefinedModelRelation: relation 'auther' is not defined on Post
}@psalm-taint-escape on closure validation rules (#1352), in inline validate() arrays, in FormRequest rules(), and when the closure is the field's whole rule. Previously the only way to assert a rule made a value safe was to extract it into a dedicated Rule class. $request->validate([
'path' => ['required', /** @psalm-taint-escape file */ static fn ($attr, $value, $fail) => /* ... */],
]);
-// TaintedFile: a closure body is opaque, so no rule could assert safety
+// cleanTaintedSql false positives on where() array values for nullable, template-bounded, and intersection builder receivers (#1338, #1350). Values in the map form are PDO-bound, but a receiver typed Builder|null, @template T of Builder, or T&Builder declined the strip. /** @param Builder|null $query */
$query->where(['status' => $request->input('status')]);
-// TaintedSql: Detected tainted SQL
+// cleanTaintedFile on uploaded-file extensions (#1324, #1325). getClientOriginalExtension() is the tail after the final dot of a normalized basename and cannot introduce a path segment, and clientExtension() returns a value from Symfony's MIME registry rather than raw client input. All other taint kinds, including include, are unchanged. Storage::putFileAs('uploads', $file, Str::ulid() . '.' . $file->getClientOriginalExtension());
-// TaintedFile: Detected tainted file handling
+// cleanSuppress cross-class taint flow through the Dispatchable traits (#1334). Psalm conflated taint nodes from the shared trait bodies, so an argument dispatched to one job appeared to reach an unrelated job's constructor sink. Genuine Bus and Event taint is still reported.
Fingerprint the migration schema cache on file contents instead of modification times (#1346). A git clone stamps every file with the checkout time, so the fingerprint changed on every CI run and the cache never hit even when the restored schema was still valid.
Full Changelog: v4.15.3...v4.15.4
Taint precision for where() array forms and redirect responses.
Taint precision for where() array forms and redirect responses.
TaintedSql false positives on where([[...]]) nested-condition arrays: a static receiver spelling (Model::where(...)) skipped the strip entirely, and the inner condition value was scalar-gated so any mixed-typed request value (the common case) kept the sink. Also closes a false negative where a Model subclass with its own concrete where() override had its real sink stripped (#1314). $term = (string) $request->input('term');
-User::where([['name', '=', $term]])->get();
-// TaintedSql (false positive) -- static receiver wasn't recognized as PDO-bound
User::where([['code', '=', $request->keyword]])->first();
-// TaintedSql (false positive) -- mixed-typed value failed the scalar gate
+// clean -- both forms are PDO-bound, matching the instance-receiver behaviorTaintedSSRF incorrectly firing alongside TaintedHeader on redirect() and the Redirector/ResponseFactory redirect family. A redirect sets a Location header for the browser to follow; the server makes no outbound request, so it's an open-redirect/header-injection sink, not SSRF (#1315).-return redirect($request->url());
-// TaintedSSRF + TaintedHeader (SSRF was mislabelled)
+return redirect($request->url());
+// TaintedHeader onlyFull Changelog: v4.15.2...v4.15.3
Taint-analysis precision for the query where() family. Resolves the TaintedSql inconsistency from #1300 (the same safe query reported or stayed silent
Taint-analysis precision for the query where() family. Resolves the TaintedSql inconsistency from #1300 (the same safe query reported or stayed silent depending on how it was written), and closes two SQL source/sink gaps.
Request::__get() as user input, so $request->term carries taint like $request->input('term') (#1305). DB::table('t')->whereRaw((string) $request->input('term')); // TaintedSql
-DB::table('t')->whereRaw((string) $request->term); // silent
+DB::table('t')->whereRaw((string) $request->term); // TaintedSqlwhereColumn() / orWhereColumn() on all three identifier positions, which the grammar emits raw (#1308).-$builder->whereColumn((string) $request->input('c'), '=', 'other'); // silent
+$builder->whereColumn((string) $request->input('c'), '=', 'other'); // TaintedSqlwhere() sql-taint strip on a Laravel builder receiver, so a non-builder where(array $parts) that interpolates raw SQL keeps its report (#1311).where() array forms raising a false TaintedSql on PDO-bound value positions; the strip now walks the array literal element-wise and keeps the sink only on raw-identifier positions (#1302, fixes #1300). $term = (string) $request->input('term');
-Model::where([['name', 'LIKE', "%{$term}%"]]); // TaintedSql (false positive)
+Model::where([['name', 'LIKE', "%{$term}%"]]); // clean — value is PDO-boundwhereLike-family $value param to mixed, matching where() and the PDO-bound runtime, so idiomatic calls stop reporting false positives (#1312).-Model::whereLike('name', $request->query('q')); // PossiblyInvalidArgument
+Model::whereLike('name', $request->query('q')); // cleanFull Changelog: v4.15.1...v4.15.2
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →