Skip to main content
📝 Laravel-Anwendungen

Laravel Prompts v0.3.15: Die CLI-Primitiven, die du gebraucht hast

Laravel Prompts v0.3.15: Die CLI-Primitiven, die du gebraucht hast Ich war letzte Woche mitten im Bau eines Deployment-Befehls für ein Kundenprojekt,...

23 min

Lesezeit

4,440

Wörter

Mar 18, 2026

Veröffentlicht

Engr Mejba Ahmed

Geschrieben von

Engr Mejba Ahmed

Artikel teilen

Laravel Prompts v0.3.15: Die CLI-Primitiven, die du gebraucht hast

Laravel Prompts v0.3.15: Die CLI-Primitiven, die du gebraucht hast

Ich war letzte Woche mitten im Bau eines Deployment-Befehls für ein Kundenprojekt, als ich an die Wand stieß, die jeder Laravel-Entwickler nur zu gut kennt. Der Befehl musste sechs aufeinanderfolgende Operationen ausführen — Abhängigkeiten ziehen, Assets kompilieren, Migrationen ausführen, Caches leeren, Routen aufwärmen und einen Health Check pingen. Jeder Schritt dauerte zwischen 3 und 45 Sekunden. Und meine Benutzererfahrung für all das? Ein blinkender Cursor. Vielleicht ein $this->info()-Aufruf zwischen den Schritten, wenn ich großzügig war.

Das Terminal saß einfach da. Still. Die Art von Stille, bei der man sich fragt, ob der Prozess hängt, ob man Strg+C drücken und von vorne anfangen sollte, oder ob die Datenbankmigration tatsächlich 200.000 Zeilen verarbeitet und man einfach warten muss.

Dann sah ich die v0.3.15 Release Notes am 17. März 2026 erscheinen. Fünf neue Primitiven. Alle aus der Laravel Cloud CLI extrahiert — dem internen Tooling, das das Laravel-Team für die Verwaltung von Cloud-Deployments gebaut hat. Das Hauptfeature ist task(), und es löst genau das Problem, das ich gerade beschrieben habe. Aber die unterstützende Besetzung — stream(), notify(), autocomplete() und title() — füllt Lücken, von denen ich nicht einmal wusste, dass ich jahrelang um sie herumgearbeitet hatte.

Ich räumte meinen Nachmittag frei und schrieb den Deployment-Befehl um. Hier ist alles, was ich herausgefunden habe.

Warum diese Primitiven existieren — und warum sie jetzt kamen

Die Hintergrundgeschichte ist hier wichtig, weil sie erklärt, warum sich diese Features von Anfang an so ausgereift anfühlen.

Als das Laravel-Team die Cloud CLI baute — das Kommandozeilentool, das deine gesamte Laravel Cloud-Infrastruktur verwaltet — brauchten sie Terminal-Interaktionen, die weit über "stelle eine Frage, bekomme eine Antwort" hinausgingen. Cloud-Deployments umfassen langlaufende Prozesse mit Echtzeit-Log-Ausgabe. Sie brauchen Spinner, die ihre Labels aktualisieren, wenn sich der Kontext ändert. Sie brauchen Statusmeldungen (Erfolg, Warnung, Fehler), die auf dem Bildschirm bestehen bleiben, während scrollende Logs darunter durchfließen. Sie brauchen Streaming-Text für KI-gestützte Operationen. Sie brauchen Desktop-Benachrichtigungen, wenn ein 10-minütiges Deployment fertig ist, während man in einem anderen Fenster arbeitet.

Nichts davon existierte vorher in Laravel Prompts. Also bauten sie es intern. Und mit v0.3.15 extrahierten sie diese Primitiven zurück in das Paket selbst — kampferprobt nach Monaten täglicher Nutzung innerhalb der Cloud CLI.

Dieses Extraktionsmuster ist eines der Dinge, die ich am Laravel-Ökosystem am meisten schätze. Features erscheinen nicht als theoretische APIs. Sie erscheinen, weil jemand sie in der Produktion brauchte, sie unter Druck baute, sie durch tägliche Nutzung verfeinerte und sie dann für alle anderen verallgemeinerte. Die task()-Funktion begann nicht als Spezifikationsdokument. Sie begann als Deployment-Bildschirm, der Ingenieure während 5-minütiger Builds auf dem Laufenden halten musste.

Mit über 179 Millionen Installationen auf Packagist und 535 abhängigen Paketen wirken sich Änderungen an Laravel Prompts auf das gesamte PHP-Ökosystem aus. Dieses Release ist kein kleiner Patch — es ist eine grundlegende Erweiterung dessen, was in Terminal-UI für PHP-Anwendungen möglich ist.

Hier ist, was tatsächlich ausgeliefert wurde.

Die task()-Funktion — Langlaufende Prozesse bekommen endlich eine echte UI

Dies ist das Herzstück von v0.3.15, und das aus gutem Grund. Die task()-Funktion gibt dir einen live aktualisierten Spinner, scrollende Log-Ausgabe, stabile Statusmeldungen, die auf dem Bildschirm bestehen bleiben, und die Möglichkeit, das Label zu aktualisieren, während die Aufgabe fortschreitet. Alles aus einem einzigen Funktionsaufruf.

Hier ist die grundlegende Signatur:

use function Laravel\Prompts\task;

task(
    title: 'Deploying application',
    callback: function ($task) {
        $task->log('Pulling latest changes...');
        // ... actual work ...

        $task->label('Compiling assets');
        $task->log('Running npm build...');
        // ... more work ...

        $task->succeed('Deployment complete');
    }
);

Was passiert, wenn das ausgeführt wird: Ein Spinner animiert neben "Deploying application." Während dein Callback läuft, schreibt jeder $task->log()-Aufruf eine Zeile in einen scrollenden Ausgabebereich unter dem Spinner. Der Log-Bereich scrollt automatisch — alte Zeilen schieben nach oben, wenn neue ankommen, sodass die neueste Ausgabe immer sichtbar bleibt. Der Spinner animiert die ganze Zeit weiter, damit der Benutzer immer weiß, dass der Prozess lebt.

Der $task->label()-Aufruf ist subtil, aber mächtig. Er ändert den Text neben dem Spinner, ohne das scrollende Log zu unterbrechen. So kannst du "Pulling dependencies" für die erste Phase anzeigen, "Compiling assets" für die zweite, "Running migrations" für die dritte — während die detaillierte Log-Ausgabe darunter weiterströmt. Zwei Ebenen der Informationsdichte: Das Label sagt dir, in welcher Phase du bist, das Log sagt dir, was gerade passiert.

Statusmeldungen, die bestehen bleiben

Der Teil, der mich überzeugt hat: stabile Statusmeldungen.

task(
    title: 'Running test suite',
    callback: function ($task) {
        $task->log('PHPUnit 11.5.2 — 342 tests');

        // Tests run...
        $task->log('Passed: UserRegistrationTest (0.234s)');
        $task->log('Passed: PaymentProcessingTest (1.203s)');

        // A warning surfaces
        $task->warning('3 tests marked as risky');

        // More tests...
        $task->log('Passed: ApiEndpointTest (0.089s)');

        $task->succeed('342 tests passed');
    }
);

Wenn du $task->warning() aufrufst, wird diese Nachricht über dem scrollenden Log-Bereich als hervorgehobene, persistente Zeile dargestellt. Sie scrollt nicht weg. Sie bleibt oben angeheftet, während der Rest des Logs darunter weiterfließt. Gleiches Verhalten für $task->error(). Und $task->succeed() schließt die Aufgabe mit einem grünen Häkchen und deiner Nachricht ab und ersetzt den Spinner.

Das löst ein Problem, um das ich jahrelang herumgehackt habe: wichtige Statusinformationen, die in ausführlicher Ausgabe untergehen. In einem Migrationsbefehl sollte die Warnung "3 Tabellen werden gelöscht" nicht in einer Wand von SQL-Statements vorbeiscrollen. Sie sollte bestehen bleiben. Jetzt tut sie das.

Die PCNTL-Anforderung

Eine Sache, die du wissen solltest: Die Spinner-Animation erfordert die pcntl PHP-Erweiterung. Unter macOS und den meisten Linux-Distributionen ist diese standardmäßig verfügbar. Unter Windows (ohne WSL) ist die PCNTL-Erweiterung nicht verfügbar — du bekommst stattdessen eine statische Fallback-Version. Die Aufgabe funktioniert trotzdem, das Log gibt trotzdem aus, aber der Spinner animiert nicht.

Prüfe, ob du sie hast:

php -m | grep pcntl

Wenn du Artisan-Befehle baust, die plattformübergreifend laufen müssen, gestalte deine Ausgabe so, dass sie auch ohne Animation nützlich ist. Die task()-Funktion handhabt das elegant — du musst keinen bedingten Code schreiben.

Mein Deployment-Befehl, neu gebaut

So sieht mein Deployment-Befehl jetzt aus im Vergleich zu vorher. Der Unterschied in der Benutzererfahrung ist dramatisch.

Vorher (die dunklen Zeiten):

public function handle()
{
    $this->info('Starting deployment...');

    // Pull code
    $this->call('down');
    $output = shell_exec('git pull origin main 2>&1');
    $this->info('Code pulled.');

    // Install dependencies
    $output = shell_exec('composer install --no-dev 2>&1');
    $this->info('Dependencies installed.');

    // Compile assets
    $output = shell_exec('npm run build 2>&1');
    $this->info('Assets compiled.');

    // Migrate
    $this->call('migrate', ['--force' => true]);
    $this->info('Migrations complete.');

    $this->call('up');
    $this->info('Done!');
}

Funktional? Sicher. Aber der Benutzer sieht 30 Sekunden lang nichts, dann einen Schwall statischen Text. Kein Hinweis auf den Fortschritt während jedes Schritts. Keine Unterscheidung zwischen "alles in Ordnung" und "etwas ist schiefgegangen, aber wir haben weitergemacht."

Nachher (v0.3.15):

use function Laravel\Prompts\task;
use function Laravel\Prompts\notify;
use function Laravel\Prompts\title;

public function handle()
{
    title('Deploy: production');

    task(
        title: 'Deploying to production',
        callback: function ($task) {
            $task->label('Pulling latest code');
            $task->log('Running git pull origin main...');

            $gitOutput = [];
            $gitCode = 0;
            exec('git pull origin main 2>&1', $gitOutput, $gitCode);

            foreach ($gitOutput as $line) {
                $task->log($line);
            }

            if ($gitCode !== 0) {
                $task->error('Git pull failed — aborting deployment');
                return;
            }

            $task->label('Installing dependencies');
            $task->log('Running composer install --no-dev...');
            exec('composer install --no-dev 2>&1', $composerOutput);

            foreach ($composerOutput as $line) {
                $task->log($line);
            }

            $task->label('Compiling assets');
            $task->log('Running npm build...');
            exec('npm run build 2>&1', $npmOutput);

            $task->label('Running migrations');
            $task->log('Applying pending migrations...');
            Artisan::call('migrate', ['--force' => true]);
            $task->log('Migrations applied.');

            $task->label('Clearing caches');
            Artisan::call('cache:clear');
            Artisan::call('config:clear');
            Artisan::call('route:clear');
            $task->log('All caches cleared.');

            $task->label('Warming caches');
            Artisan::call('config:cache');
            Artisan::call('route:cache');
            $task->log('Caches warmed.');

            $task->succeed('Deployment complete — all systems operational');
        }
    );

    title('Deploy: complete');

    notify(
        title: 'Deployment Complete',
        body: 'Production deployment finished successfully.'
    );
}

Das Terminal zeigt jetzt während jeder Phase einen drehenden Indikator, das Label aktualisiert sich, während der Befehl durch die Phasen fortschreitet, jede Zeile echte Ausgabe von git, Composer und npm strömt in das scrollende Log, Fehler erscheinen sofort als angeheftete Statusmeldungen, und wenn es fertig ist, erscheint eine native Desktop-Benachrichtigung. Dieser letzte Teil — die Benachrichtigung — bringt uns zum nächsten Primitiv.

notify() — Native Desktop-Benachrichtigungen aus PHP

Das hat mich überrascht. Nicht weil Desktop-Benachrichtigungen ein neues Konzept sind, sondern weil ich sie nie von einem PHP CLI-Tool erwartet hätte.

use function Laravel\Prompts\notify;

notify(
    title: 'Build Complete',
    body: 'Your application has been compiled and deployed.'
);

Das ist alles. Eine native Betriebssystem-Benachrichtigung erscheint — die gleiche Art, die du von Slack, VS Code oder deinem E-Mail-Client bekommst. Unter macOS nutzt sie das System-Benachrichtigungszentrum. Unter Linux funktioniert sie über den Standard-Benachrichtigungsdienst. Unter Windows mit WSL leitet sie an Windows-Benachrichtigungen weiter.

Der Anwendungsfall, der bei mir sofort klickte: langlaufende Artisan-Befehle, die ich starte und dann vergesse. Ich starte ein Database Seeding, das 8 Minuten dauert, wechsle zu meinem Editor, beginne an etwas anderem zu arbeiten und vergesse das Terminal komplett. Zwanzig Minuten später frage ich mich "war das schon fertig?" und muss nachschauen.

Jetzt füge ich eine Zeile am Ende des Befehls hinzu. Die Benachrichtigung findet mich, wo auch immer ich bin.

public function handle()
{
    // ... 8 minutes of seeding ...

    notify(
        title: 'Database Seeded',
        body: sprintf('%d records created in %d seconds.', $count, $elapsed)
    );
}

Eine Kleinigkeit. Aber Kleinigkeiten, die kognitive Belastung eliminieren, summieren sich zu einer wirklich besseren Entwicklungserfahrung.

stream() — Text, der sich selbst ins Terminal tippt

Wenn task() das Arbeitstier dieser Release ist, dann ist stream() das Schaustück. Es zeigt Text, der Zeichen für Zeichen (oder Stück für Stück) ins Terminal fließt, mit einem allmählichen Einblendeffekt.

use function Laravel\Prompts\stream;

$stream = stream('Processing analysis');

$stream->append('Analyzing codebase structure... ');
$stream->append("found 342 files.\n");
$stream->append('Identifying patterns... ');
$stream->append("detected 12 architectural concerns.\n");
$stream->append('Generating recommendations...');

$stream->close();

Die append()-Methode fügt Text mit einem visuellen Einblendeffekt hinzu — Zeichen materialisieren sich schrittweise, anstatt alle auf einmal zu erscheinen. Das klingt vielleicht nach Spielerei, bis du den primären Anwendungsfall bedenkst: KI-generierte Inhalte im Terminal anzeigen.

Wenn du Artisan-Befehle baust, die OpenAI, Anthropic oder eine andere LLM API mit Streaming-Antworten aufrufen, gibt dir stream() den gleichen Schreibmaschinen-Effekt, den du in der ChatGPT-Oberfläche siehst — aber in deinem Terminal. Der Text kommt an, während das Modell ihn generiert, und stream() rendert ihn mit dieser befriedigenden schrittweisen Enthüllung.

use function Laravel\Prompts\stream;
use OpenAI\Laravel\Facades\OpenAI;

$stream = stream('AI Analysis');

$response = OpenAI::chat()->createStreamed([
    'model' => 'gpt-4o',
    'messages' => [
        ['role' => 'user', 'content' => 'Analyze this error log...'],
    ],
]);

foreach ($response as $chunk) {
    $text = $chunk->choices[0]->delta->content ?? '';
    $stream->append($text);
}

$stream->close();

Die close()-Methode schließt die Ausgabe ab, stellt den Cursor wieder her und signalisiert, dass das Streaming abgeschlossen ist. Ohne sie würde das Terminal in einem unbestimmten Zustand verbleiben.

Ich kann bereits sehen, dass dies zum Standard in KI-gesteuerten Artisan-Befehlen wird — die Art von Tooling, die in Laravel-Anwendungen schnell zur Normalität wird, seit das Ökosystem KI-Integrationen im Laufe von 2025 und bis 2026 übernommen hat. Ein erstklassiges Rendering-Primitiv für gestreamten Text ist genau die grundlegende Unterstützung, die das Paket brauchte.

autocomplete() — Geistertext im Terminal

Die autocomplete()-Funktion fügt Inline-Autovervollständigung zu Texteingaben hinzu und zeigt Vorschläge als Geistertext, den der Benutzer mit Tab oder der Pfeiltaste nach rechts akzeptieren kann.

use function Laravel\Prompts\autocomplete;

$framework = autocomplete(
    label: 'Which framework?',
    options: fn (string $value) => collect([
        'Laravel', 'Symfony', 'Slim', 'Lumen', 'CakePHP',
    ])
        ->filter(fn ($item) => str_contains(
            strtolower($item),
            strtolower($value)
        ))
        ->values()
        ->all()
);

Tippe "la" und "Laravel" erscheint als verblasster Geistertext nach deinem Cursor. Drücke Tab, um es zu akzeptieren. Wenn du weiter "lum" tippst, wechselt der Geistertext zu "Lumen." Der Options-Callback empfängt den aktuellen Eingabewert und gibt passende Vorschläge in Echtzeit zurück.

Der Unterschied zwischen autocomplete() und der bestehenden suggest()-Funktion ist das Interaktionsmodell. suggest() zeigt eine Dropdown-Liste passender Optionen unter der Eingabe. autocomplete() zeigt Inline-Geistertext — das gleiche Muster, das du von GitHub Copilot, deiner IDE oder modernen Browser-Adressleisten kennst. Es ist schneller für erfahrene Benutzer, die wissen, was sie wollen, und nur das System brauchen, um ihren Gedanken zu Ende zu bringen.

Wann greifst du zu welchem?

  • suggest() funktioniert, wenn der Benutzer Optionen durchstöbert und mehrere Treffer gleichzeitig sehen muss
  • autocomplete() funktioniert, wenn der Benutzer ungefähr die Antwort kennt und Geschwindigkeit will — weniger Tastenanschläge, schnellerer Ablauf

Für Befehle, die erfahrene Entwickler täglich ausführen — Umgebungen auswählen, Branches wählen, Modellnamen angeben — wird sich autocomplete() spürbar flüssiger anfühlen als suggest().

title() — Den Terminalfenstertitel setzen

Dieser ist trügerisch einfach:

use function Laravel\Prompts\title;

title('Application Installer');

Er ändert den Titel des Terminalfensters oder Tabs. Das ist alles. Der Text in der Titelleiste oder Tab-Beschriftung deines Terminals wird auf den übergebenen String aktualisiert.

Warum ist das wichtig? Weil jeder, der mehr als drei Terminal-Tabs gleichzeitig offen hat, den Schmerz kennt, den richtigen zu finden. Wenn dein Artisan-Befehl den Titel auf "Deploying: staging" oder "Queue Worker: emails" oder "Migrating: production" setzt, wird das Finden des richtigen Tabs zum Kinderspiel.

Kombiniere es mit notify() für langlaufende Befehle:

title('Deploy: production');

task(
    title: 'Running deployment',
    callback: function ($task) {
        // ... deployment steps ...
        $task->succeed('All clear');
    }
);

title('Deploy: complete');

notify(
    title: 'Production Deploy',
    body: 'Finished at ' . now()->format('H:i:s')
);

Der Terminal-Tab verrät dir den Status auf einen Blick. Die Benachrichtigung holt dich zurück, wenn du woanders bist. Zwei Primitiven, und dein Deployment-Befehl respektiert deine Aufmerksamkeit, anstatt sie einzufordern.

Alles zusammenfügen — Ein Praxis-Befehl

Einzelne Primitiven sind interessant. Kombiniert sind sie transformativ. Hier ist ein vollständiger Artisan-Befehl, der jedes neue v0.3.15-Feature nutzt — die Art von Befehl, den du tatsächlich für einen Produktions-Workflow bauen könntest:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use function Laravel\Prompts\autocomplete;
use function Laravel\Prompts\task;
use function Laravel\Prompts\stream;
use function Laravel\Prompts\notify;
use function Laravel\Prompts\title;
use function Laravel\Prompts\info;

class AnalyzeCodebase extends Command
{
    protected $signature = 'analyze {--fix}';
    protected $description = 'Run AI-powered codebase analysis';

    public function handle()
    {
        title('Codebase Analysis');

        $scope = autocomplete(
            label: 'What should I analyze?',
            options: fn (string $value) => collect([
                'Full codebase',
                'Controllers only',
                'Models only',
                'Routes and middleware',
                'Database migrations',
                'Test coverage',
            ])
                ->filter(fn ($item) => str_contains(
                    strtolower($item),
                    strtolower($value)
                ))
                ->values()
                ->all()
        );

        // Phase 1: Scan with task()
        $results = [];

        task(
            title: 'Scanning codebase',
            callback: function ($task) use ($scope, &$results) {
                $task->label('Discovering files');
                $task->log("Scope: {$scope}");

                $files = $this->discoverFiles($scope);
                $task->log(count($files) . ' files found.');

                $task->label('Analyzing patterns');

                foreach ($files as $file) {
                    $task->log("Scanning: {$file}");
                    $results[] = $this->analyzeFile($file);
                }

                $issues = collect($results)->where('has_issues', true);

                if ($issues->count() > 10) {
                    $task->warning($issues->count() . ' files with issues detected');
                }

                $task->succeed(
                    count($files) . ' files scanned, '
                    . $issues->count() . ' issues found'
                );
            }
        );

        // Phase 2: AI analysis with stream()
        $analysis = stream('Generating recommendations');

        foreach ($this->getAiAnalysis($results) as $chunk) {
            $analysis->append($chunk);
        }

        $analysis->close();

        // Phase 3: Signal completion
        title('Analysis: complete');

        notify(
            title: 'Analysis Complete',
            body: count($results) . ' files analyzed. Check your terminal.'
        );
    }
}

Das ist ein einziger Artisan-Befehl, der title() für Tab-Identifikation nutzt, autocomplete() für schnelle Eingabe, task() für die schwere Arbeit mit Echtzeit-Fortschritt, stream() für KI-generierte Ausgabe und notify() für das Fertigstellungssignal. Vor sechs Monaten hätte der Bau dieses Niveaus an Terminal-UX in PHP eine Drittanbieter-Bibliothek oder hunderte Zeilen benutzerdefinierter Renderer-Code erfordert. Jetzt ist es eine Handvoll Funktionsaufrufe.

Was sonst noch kürzlich erschien — Die begleitenden Releases

Die v0.3.15-Features erschienen nicht isoliert. Die vorangegangenen Releases legten das Fundament:

v0.3.12 (Februar 2026) fügte Laravel 13-Unterstützung hinzu und behob die Validierungsbehandlung für den Number Prompt — die numerische Eingabe, die in v0.3.11 eingeführt wurde und es Benutzern ermöglicht, mit Pfeiltasten zu erhöhen und zu verringern und Min/Max-Beschränkungen durchzusetzen.

v0.3.10 (Januar 2026) führte die Grid-Komponente für Layout-Organisation innerhalb von Terminal-Interfaces ein. Stell es dir als grundlegendes Flexbox für die CLI vor — mehrere Elemente nebeneinander positionieren, anstatt alles vertikal zu stapeln.

v0.3.15 lieferte außerdem dynamische sekundäre Informationen für Select-Typ-Prompts. Du kannst jetzt einen Callback übergeben, der sekundären Detailtext für jede Option generiert, der neben dem Optionslabel angezeigt wird. Nützlich, um Beschreibungen, Metadaten oder Statusindikatoren neben jeder Auswahl in einem select()- oder multiselect()-Aufruf anzuzeigen.

Und eine PHPStan-Bereinigung, die die Typsicherheit über das gesamte Paket verbesserte — die Art unsichtbarer Arbeit, die die Bibliothek zuverlässiger für IDE-Autovervollständigung und statische Analyse in deinen eigenen Projekten macht.

Die Primitiven, die du schon hattest (aber möglicherweise zu wenig nutzt)

Da wir gerade über das vollständige Prompts-Toolkit sprechen, hier eine kurze Bestandsaufnahme der bestehenden Primitiven, die sich gut mit den v0.3.15-Ergänzungen kombinieren lassen. Ich liste sie auf, weil die meisten Laravel-Entwickler, mit denen ich spreche, nur select() und confirm() verwenden — und damit erhebliches Terminal-UX-Potenzial ungenutzt lassen.

Informative Nachrichtenfunktionen:

use function Laravel\Prompts\info;
use function Laravel\Prompts\note;
use function Laravel\Prompts\warning;
use function Laravel\Prompts\error;
use function Laravel\Prompts\alert;

info('Migration complete.');         // Blue, informational
note('Check the logs for details.'); // Gray, subtle
warning('3 deprecated methods.');    // Yellow, cautionary
error('Connection refused.');        // Red, critical
alert('Action required!');           // Bold, attention-demanding

Tabellen für strukturierte Ausgabe:

use function Laravel\Prompts\table;

table(
    headers: ['Migration', 'Status', 'Duration'],
    rows: [
        ['2026_03_01_create_users', 'Applied', '0.34s'],
        ['2026_03_02_create_orders', 'Applied', '1.21s'],
        ['2026_03_03_add_indexes', 'Pending', '---'],
    ]
);

Fortschrittsbalken für iterierbare Operationen:

use function Laravel\Prompts\progress;

$results = progress(
    label: 'Importing records',
    steps: $csvRows,
    callback: function ($row) {
        return $this->importRow($row);
    }
);

Spin für einfache Ladezustände:

use function Laravel\Prompts\spin;

$result = spin(
    message: 'Fetching remote configuration...',
    callback: fn () => Http::get('https://api.example.com/config')->json()
);

Der Unterschied zwischen spin() und task() ist der Umfang. spin() ist für einfache Operationen, bei denen du nur "bitte warten" mit einem Spinner und einer einzelnen Nachricht brauchst. task() ist für Mehrphasen-Operationen mit scrollender Log-Ausgabe, Label-Updates und persistenten Statusmeldungen. Verwende spin() für einen 3-Sekunden-API-Aufruf. Verwende task() für ein 3-Minuten-Deployment.

Wie du das richtige Primitiv wählst — Ein Entscheidungsrahmen

Nach einer Woche, in der ich Befehle mit diesen Tools umgeschrieben habe, bin ich bei einem mentalen Modell für die Wahl zwischen ihnen angelangt:

Verwende task() wenn:

  • Die Operation länger als 5 Sekunden dauert
  • Es mehrere Phasen gibt, über die der Benutzer Bescheid wissen sollte
  • Du Log-Ausgabe hast, die der Benutzer möglicherweise lesen möchte
  • Fehler oder Warnungen auf dem Bildschirm bestehen bleiben müssen
  • Du das Label aktualisieren willst, während die Operation fortschreitet

Verwende spin() wenn:

  • Die Operation ein einzelner Schritt ohne sinnvolle Log-Ausgabe ist
  • Sie in unter 10 Sekunden fertig ist
  • Du nur "bitte warten, das arbeitet" brauchst

Verwende stream() wenn:

  • Du KI-generierten oder gestreamten Text renderst
  • Die Ausgabe schrittweise erscheinen soll, nicht auf einmal
  • Du den Schreibmaschinen-/Einblend-Effekt willst

Verwende progress() wenn:

  • Du über eine bekannte Anzahl von Elementen iterierst
  • Jede Iteration ungefähr gleich lang dauert
  • Der Benutzer von "47 von 200 abgeschlossen" profitiert

Verwende autocomplete() wenn:

  • Der Benutzer ungefähr weiß, was er tippen will
  • Geschwindigkeit wichtiger ist als das Durchsuchen einer vollständigen Liste
  • Du eine kleine bis mittlere Menge vorhersehbarer Optionen hast

Verwende suggest() wenn:

  • Der Benutzer mehrere Treffer gleichzeitig sehen muss
  • Die Optionsmenge groß ist und vom visuellen Scannen profitiert
  • Entdeckung wichtiger ist als Geschwindigkeit

Verwende notify() wenn:

  • Der Befehl lange genug läuft, dass der Benutzer das Fenster wechseln könnte
  • Die Fertigstellung ein Ereignis ist, für das es sich lohnt, unterbrochen zu werden
  • Du mehrere Terminal-Tabs gleichzeitig laufen hast

Verwende title() wenn:

  • Der Befehl in einem dauerhaften Terminal-Tab läuft
  • Du mehrere ähnliche Befehle in verschiedenen Tabs hast
  • Du auf einen Blick erkennen willst, was jedes Terminal tut

Wenn du lieber jemanden diese Art von polierten CLI-Tools und Deployment-Workflows für dein Team bauen lässt, übernehme ich Laravel-Beratung und maßgeschneiderte Artisan-Tooling-Aufträge. Du kannst sehen, was ich gebaut habe, auf fiverr.com/s/EgxYmWD.

Das große Ganze — PHP CLI wird erwachsen

Hier ist, was mich an diesem Release beeindruckt. Jahrelang war Terminal-UX in PHP ein nachträglicher Gedanke. Du hattest die Helpers von Symfony Console — Fortschrittsbalken, Tabellen, Frage-Helper — und die waren okay. Funktional. Nicht schön. Einfach okay.

Laravel Prompts änderte diese Richtung, als es 2023 mit Laravel 10 gestartet wurde. Aber das erste Release konzentrierte sich auf Eingabe — text, select, multiselect, confirm. Informationen vom Benutzer auf elegante Weise zu bekommen. Die Ausgabe-Seite — Informationen an den Benutzer während Operationen zu zeigen — war immer noch rudimentär. $this->info() und $this->error() und gelegentlich ein Fortschrittsbalken.

v0.3.15 vervollständigt das Bild. Eingabe und Ausgabe sind jetzt beide erstklassig. Du kannst eine CLI-Erfahrung bauen, die mit dem konkurriert, was du von einem Node.js-Tool mit Ink oder einem Rust-Tool mit Ratatui erwarten würdest. Spinner, Streaming-Text, live aktualisierende Labels, persistente Statusmeldungen, native Benachrichtigungen, Terminal-Titelverwaltung — das sind die Bausteine, die den Unterschied zwischen einem "Befehl" und einem "Erlebnis" ausmachen.

Und die Tatsache, dass diese aus der Cloud CLI extrahiert wurden, bedeutet, dass sie den härtesten Test bereits bestanden haben: echte Ingenieure, die sie jeden Tag unter realen Bedingungen nutzen. Der Spinner musste flüssig sein. Das Log-Scrolling musste schnelle Ausgabe ohne Flackern bewältigen. Die Benachrichtigungen mussten tatsächlich zuverlässig auf macOS, Linux und WSL erscheinen. Das sind keine theoretischen Features — es sind produktionsgehärtete.

Für das Laravel-Ökosystem im Speziellen denke ich, dass dieses Release einen Wendepunkt markiert. Artisan-Befehle waren auf der Logik-Seite immer leistungsstark. Jetzt können sie auch auf der Erlebnis-Seite leistungsstark sein. Und in einer Ära, in der Entwickler zunehmend Tools danach auswählen, wie sie sich anfühlen — nicht nur danach, was sie tun — macht diese Unterscheidung mehr aus, als die meisten Menschen erkennen.

Was ich als Nächstes sehen möchte

Die Primitiven sind da. Das Fundament ist solide. Aber es gibt Lücken, die ich beobachte.

Zusammensetzbare Layouts. Die Grid-Komponente aus v0.3.10 ist ein Anfang, aber ich möchte die Möglichkeit, einen task()-Spinner neben einer table() zu platzieren, die sich in Echtzeit aktualisiert. Nebeneinander-Elemente. Dashboard-artige Layouts. Die Cloud CLI hat wahrscheinlich intern etwas davon — ich hoffe, dass mehr davon extrahiert wird.

Tastaturkürzel innerhalb von Tasks. Stell dir vor, du drückst "v", um ausführliches Logging umzuschalten, oder "s", um den aktuellen Schritt zu überspringen. Interaktive Tasks, nicht nur Anzeige-Tasks. Die pcntl-Erweiterung ermöglicht bereits Signalbehandlung — die Erweiterung auf Tastenerkennung innerhalb eines laufenden Tasks fühlt sich wie der natürliche nächste Schritt an.

Theme-Unterstützung. Das aktuelle Rendering ist wunderschön, aber es ist eine einzige Ästhetik. Verschiedene Projekte haben verschiedene Terminal-Umgebungen. Eine Theme-API — selbst eine einfache, die es erlaubt, Farben und Symbole zu überschreiben — würde Prompts in jedem Team-Tooling-Setup heimisch wirken lassen.

Nichts davon ist Kritik. v0.3.15 ist ein wirklich starkes Release. Aber die Richtung, die es vorgibt, ist wohl noch aufregender als das, was es geliefert hat. Die Kluft zwischen "PHP CLI-Tool" und "polierte Terminal-Anwendung" ist gerade deutlich kleiner geworden.

Fang mit einem Befehl an

Wähle einen Artisan-Befehl in deinem Projekt — den, der am längsten dauert, den, der den meisten Text ausgibt, den, den dein Team meidet, weil die Erfahrung schmerzhaft ist. Schreib ihn mit task() um. Füge ein notify() am Ende hinzu. Setze den title() am Anfang.

Es dauert 30 Minuten. Der Befehl macht genau das, was er vorher gemacht hat. Aber er fühlt sich wie ein anderes Werkzeug an. Und wenn das nächste Mal jemand in deinem Team ihn ausführt, wird er es bemerken. Das ist die Art von Upgrade, die nichts kostet und alles daran ändert, wie dein Tooling wahrgenommen wird.

Die Primitiven sind da. Composer hat sie bereits:

composer require laravel/prompts:^0.3.15

Oder wenn du auf Laravel 12 oder 13 bist, sind sie bereits gebündelt. Fang einfach an, die Funktionen zu verwenden.

Ein Befehl. Dreißig Minuten. Los geht's.

Häufig gestellte Fragen

Funktioniert Laravel Prompts task() unter Windows?

Die task()-Funktion funktioniert auf allen Plattformen, aber der animierte Spinner erfordert die PCNTL PHP-Erweiterung, die unter nativem Windows nicht verfügbar ist. Unter Windows wird stattdessen ein statischer Fallback gerendert. Die Verwendung von WSL unter Windows gibt dir volle Animationsunterstützung, da es einen echten Linux-Kernel ausführt.

Was ist der Unterschied zwischen spin() und task() in Laravel Prompts?

spin() ist für einfache Einzelschritt-Operationen, bei denen du einen Spinner und eine Nachricht brauchst. task() ist für Mehrphasen-Operationen mit scrollender Log-Ausgabe, dynamischen Label-Updates und persistenten Erfolgs-/Warnungs-/Fehlermeldungen. Verwende spin() für schnelle API-Aufrufe unter 10 Sekunden; verwende task() für Deployments, Migrationen und mehrstufige Builds.

Kann ich Laravel Prompts stream() für KI-generierten Text verwenden?

Ja — stream() wurde speziell für diesen Anwendungsfall entwickelt. Rufe $stream->append() mit jedem Chunk einer Streaming-LLM-API-Antwort auf, und der Text wird mit einem progressiven Einblendeffekt gerendert. Rufe $stream->close() auf, wenn der Stream endet, um die Ausgabe abzuschließen und den Cursor wiederherzustellen.

Welche PHP-Version erfordert Laravel Prompts v0.3.15?

Laravel Prompts v0.3.15 erfordert PHP 8.1 oder höher und die ext-mbstring-Erweiterung. Es funktioniert mit Symfony Console 6.2, 7.0 und 8.0 und wird mit Laravel 12 und Laravel 13 gebündelt ausgeliefert.

Wie sende ich Desktop-Benachrichtigungen aus einem Laravel Artisan-Befehl?

Verwende die notify()-Funktion von Laravel Prompts v0.3.15: notify(title: 'Done', body: 'Your task finished.'). Sie sendet eine native OS-Benachrichtigung unter macOS (Notification Center), Linux (Benachrichtigungsdienst) und Windows über WSL. Keine zusätzlichen Pakete oder Konfiguration erforderlich.

Let's Work Together

Looking to build AI systems, automate workflows, or scale your tech infrastructure? I'd love to help.

Coffee cup

Hat Ihnen dieser Artikel gefallen?

Ihre Unterstützung hilft mir, mehr tiefgehende technische Inhalte, Open-Source-Tools und kostenlose Ressourcen für die Entwickler-Community zu erstellen.

Verwandte Themen

Engr Mejba Ahmed

Über den Autor

Engr Mejba Ahmed

Engr. Mejba Ahmed builds AI-powered applications and secure cloud systems for businesses worldwide. With 10+ years shipping production software in Laravel, Python, and AWS, he's helped companies automate workflows, reduce infrastructure costs, and scale without security headaches. He writes about practical AI integration, cloud architecture, and developer productivity.

Discussion

Comments

0

No comments yet

Be the first to share your thoughts

Leave a Comment

Your email won't be published

7  x  7  =  ?

Weiter lernen

Verwandte Artikel

Alle anzeigen

Comments

Leave a Comment

Comments are moderated before appearing.

Learning Resources

Expand Your Knowledge

Accelerate your growth with structured courses, verified certificates, interactive flashcards, and production-ready AI agent skills.

Sample Certificate of Completion

Sample certificate — complete any course to earn yours