### Run a Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Instantiate a workflow using WorkflowStub and start its execution. This example demonstrates how to start a workflow, wait for it to complete, and retrieve its output. ```php use Workflow\WorkflowStub; $workflow = WorkflowStub::make(MyWorkflow::class); $workflow->start('world'); while ($workflow->running()); $workflow->output(); // Output: 'Hello, world!' ``` -------------------------------- ### Install Waterline UI Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-11-19-waterline-ui.md Use this command to install the Waterline package and publish its assets. This setup is required to access the Waterline UI at the /waterline URL. ```bash composer require durable-workflow/waterline php artisan waterline:publish ``` -------------------------------- ### Initialize App and Start Queue Worker Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-07-10-building-reliable-agentic-loops-with-laravel-workflow-and-prismphp.md Run these commands to set up the application and start the queue worker for processing tasks. ```bash php artisan app:init php artisan queue:work ``` -------------------------------- ### Start Local Development Server Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/README.md Starts a local development server for live previewing changes. Changes are reflected live without server restarts. ```bash $ yarn start ``` -------------------------------- ### Install Finite State Machine Library Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-04-25-combining-laravel-workflow-and-state-machines.md Use Composer to install the Finite state machine library for managing explicit state transitions. ```bash composer require yohang/finite ``` -------------------------------- ### Install Dependencies Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/README.md Run this command to install project dependencies using Yarn. ```bash $ yarn ``` -------------------------------- ### Create and Run Loan Application Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-04-25-combining-laravel-workflow-and-state-machines.md Instantiate, start, and signal a LoanApplicationWorkflow. Ensure the workflow is started before signaling. The output reflects the final state after signals are processed. ```php $workflow = WorkflowStub::make(LoanApplicationWorkflow::class); // start workflow $workflow->start(); sleep(1); // submit signal $workflow->submit(); sleep(1); // approve signal $workflow->approve(); sleep(1); $workflow->output(); // "approved" ``` -------------------------------- ### Run Microservice Coordination Sample Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-05-08-learning-durable-workflow-from-the-sample-app.md Starts the sample workflow that coordinates microservices. This showcases inter-service communication patterns. ```bash php artisan app:microservice ``` -------------------------------- ### Install Workflow and Spatie Laravel Tags Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-28-extending-laravel-workflow-to-support-spatie-laravel-tags.md Install the necessary packages using Composer. Ensure you have both `laravel-workflow` and `spatie/laravel-tags`. ```sh composer require laravel-workflow/laravel-workflow spatie/laravel-tags ``` -------------------------------- ### Start Video Conversion Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-31-converting-videos-with-ffmpeg.md Initiates the execution of the defined ConvertVideoWorkflow. This is the entry point for starting the background video conversion process. ```php WorkflowStub::make(ConvertVideoWorkflow::class)->start(); ``` -------------------------------- ### Create Start Workflow Tool Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Use this Artisan command to generate the StartWorkflowTool class. ```bash php artisan make:mcp-tool StartWorkflowTool ``` -------------------------------- ### Start Workflow Tool Implementation Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md This PHP class handles starting workflows asynchronously. It validates input, resolves workflow classes, and returns the workflow ID and status. Ensure the workflow configuration is set up correctly. ```php namespace App\Mcp\Tools; use Illuminate\Contracts\JsonSchema\JsonSchema; use Illuminate\Support\Arr; use Laravel\Mcp\Request; use Laravel\Mcp\Response; use Laravel\Mcp\Server\Tool; use Workflow\Workflow; use Workflow\WorkflowStub; class StartWorkflowTool extends Tool { protected string $description = <<<'MARKDOWN' Start a Workflow asynchronously and return its workflow ID. The workflow will execute in the background on the queue. Use the `get_workflow_result` tool to poll for status and retrieve results once the workflow completes. MARKDOWN; public function handle(Request $request): Response { $data = $request->validate([ 'workflow' => ['required', 'string'], 'args' => ['nullable', 'array'], 'external_id' => ['nullable', 'string', 'max:255'], ]); $workflowKey = $data['workflow']; $args = Arr::get($data, 'args', []); $externalId = $data['external_id'] ?? null; $workflowClass = $this->resolveWorkflowClass($workflowKey); if ($workflowClass === null) { return Response::error("Unknown workflow: {$workflowKey}"); } if (! class_exists($workflowClass) || ! is_subclass_of($workflowClass, Workflow::class)) { return Response::error("Invalid workflow class: {$workflowClass}"); } $stub = WorkflowStub::make($workflowClass); $stub->start(...array_values($args)); $status = $stub->status(); $statusName = is_object($status) ? class_basename($status) : class_basename((string) $status); return Response::json([ 'workflow_id' => $stub->id(), 'workflow' => $workflowKey, 'status' => $statusName, 'external_id' => $externalId, 'message' => 'Workflow started. Use get_workflow_result to poll status.', ]); } protected function resolveWorkflowClass(string $key): ?string { $mapped = config("workflow_mcp.workflows.{$key}"); if ($mapped !== null) { return $mapped; } if (config('workflow_mcp.allow_fqcn', false) && str_contains($key, '\\')) { return $key; } return null; } public function schema(JsonSchema $schema): array { $workflows = implode(', ', array_keys(config('workflow_mcp.workflows', []))); return [ 'workflow' => $schema->string() ->description("The workflow to start. Available: {$workflows}"), 'args' => $schema->object() ->description('Arguments for the workflow execute() method.'), 'external_id' => $schema->string() ->description('Optional idempotency key for tracking.'), ]; } } ``` -------------------------------- ### Install Laravel Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-04-25-combining-laravel-workflow-and-state-machines.md Use Composer to install the Laravel Workflow package in your project. ```bash composer require laravel-workflow/laravel-workflow ``` -------------------------------- ### Install Laravel MCP Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Install the Laravel MCP package and publish AI-related routes to your application. ```bash composer require laravel/mcp php artisan vendor:publish --tag=ai-routes ``` -------------------------------- ### Run Queue Worker and Sample App Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-05-08-learning-durable-workflow-from-the-sample-app.md Starts the queue worker and the sample application's artisan command. Ensure the queue worker is running to process tasks. ```bash php artisan queue:work ``` ```bash php artisan app:workflow ``` -------------------------------- ### Start Image Moderation Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-20-ai-image-moderation-with-laravel-workflow.md Initiates the ImageModerationWorkflow by starting it with an initial image path. Requires WorkflowStub to be available. ```php $workflow = WorkflowStub::make(ImageModerationWorkflow::class); $workflow->start('tmp/good.jpg'); ``` -------------------------------- ### Start Workflow Tool Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md This tool allows you to start a workflow asynchronously. The workflow executes in the background on the queue. You can use the `get_workflow_result` tool to poll for status and retrieve results. ```APIDOC ## POST /api/tools/start-workflow ### Description Starts a Workflow asynchronously and returns its workflow ID. The workflow will execute in the background on the queue. Use the `get_workflow_result` tool to poll for status and retrieve results once the workflow completes. ### Method POST ### Endpoint /api/tools/start-workflow ### Parameters #### Request Body - **workflow** (string) - Required - The workflow to start. Available workflows are listed in the schema description. - **args** (array) - Optional - Arguments for the workflow execute() method. - **external_id** (string) - Optional - Idempotency key for tracking. Maximum length is 255 characters. ### Request Example ```json { "workflow": "ExampleWorkflow", "args": ["argument1", 123], "external_id": "unique-request-id-123" } ``` ### Response #### Success Response (200) - **workflow_id** (string) - The unique identifier for the started workflow. - **workflow** (string) - The key or name of the started workflow. - **status** (string) - The initial status of the workflow (e.g., 'Pending'). - **external_id** (string) - The provided external ID, if any. - **message** (string) - A confirmation message indicating the workflow has started. #### Response Example ```json { "workflow_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "workflow": "ExampleWorkflow", "status": "Pending", "external_id": "unique-request-id-123", "message": "Workflow started. Use get_workflow_result to poll status." } ``` #### Error Response (400) - **error** (string) - A message indicating the error, e.g., 'Unknown workflow' or 'Invalid workflow class'. #### Error Response Example ```json { "error": "Unknown workflow: NonExistentWorkflow" } ``` ``` -------------------------------- ### Define an Activity Class Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Create an activity class that extends the base Activity class. This example defines a simple activity that returns a greeting. ```php use Workflow\Activity; class MyActivity extends Activity { public function execute($name) { return "Hello, {$name}!"; } } ``` -------------------------------- ### Create and Run Tagged Workflow Command Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-28-extending-laravel-workflow-to-support-spatie-laravel-tags.md Create a console command to demonstrate creating a workflow, tagging it, retrieving it by tag, and starting its execution. This showcases the integrated functionality. ```php namespace App\Console\Commands; use App\Models\StoredWorkflow; use App\Workflows\Simple\SimpleWorkflow; use Illuminate\Console\Command; use Workflow\WorkflowStub; class Workflow extends Command { protected $signature = 'workflow'; protected $description = 'Runs a workflow'; public function handle() { // Create a workflow and tag it $workflow = WorkflowStub::make(SimpleWorkflow::class); StoredWorkflow::tag($workflow, 'tag1'); // Find the workflow by tag and start it $workflow = StoredWorkflow::findByTag('tag1'); $workflow->start(); while ($workflow->running()); $this->info($workflow->output()); } } ``` -------------------------------- ### Trigger Prism AI Workflow from Console Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-07-10-building-reliable-agentic-loops-with-laravel-workflow-and-prismphp.md Use this command to initiate the Prism AI workflow. It starts the workflow, waits for it to complete, and then displays the generated user output. ```php use App\Workflows\Prism\PrismWorkflow; use Illuminate\Console\Command; use Workflow\WorkflowStub; class Prism extends Command { protected $signature = 'app:prism'; protected $description = 'Runs a Prism AI workflow'; public function handle() { $workflow = WorkflowStub::make(PrismWorkflow::class); $workflow->start(); while ($workflow->running()); $user = $workflow->output(); $this->info('Generated User:'); $this->info(json_encode($user, JSON_PRETTY_PRINT)); } } ``` -------------------------------- ### Define a Workflow Class Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Create a workflow class that extends the base Workflow class. This example shows a simple workflow that executes a single activity. ```php use function Workflow\activity; use Workflow\Workflow; class MyWorkflow extends Workflow { public function execute($name) { $result = yield activity(MyActivity::class, $name); return $result; } } ``` -------------------------------- ### Run Playwright Workflow Command Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-02-07-automating-qa-with-playwright-and-laravel-workflow.md This Artisan command initiates the Playwright workflow. It starts the workflow, waits for it to complete, and then displays the path to the converted MP4 video. Ensure the workflow class and its dependencies are correctly set up. ```php namespace App\Console\Commands; use App\Workflows\Playwright\CheckConsoleErrorsWorkflow; use Illuminate\Console\Command; use Workflow\WorkflowStub; class Playwright extends Command { protected $signature = 'app:playwright'; protected $description = 'Runs a playwright workflow'; public function handle() { $workflow = WorkflowStub::make(CheckConsoleErrorsWorkflow::class); $workflow->start('https://example.com'); while ($workflow->running()); $this->info($workflow->output()['mp4']); } } ``` -------------------------------- ### Create ListWorkflowsTool Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Generates a new tool for listing available workflow types and recent runs. This tool requires a valid Laravel MCP setup. ```bash php artisan make:mcp-tool ListWorkflowsTool ``` -------------------------------- ### Simple Activity Implementation Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-12-22-new-laravel-workflow-feature-side-effects.md A basic activity that returns its input unmodified. This is used in the side effect example to verify the deterministic behavior of wrapped side effects. ```php class SimpleActivity extends Activity { public function execute($input) { return $input; } } ``` -------------------------------- ### Saga Compensation Example: Hotel Booking Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-02-07-building-a-durable-ai-travel-agent-with-laravel.md Illustrates the compensation process for a hotel booking. After a `BookHotelActivity` successfully completes, a corresponding `CancelHotelActivity` is registered as a compensation action. This ensures that if any subsequent step fails, the hotel booking can be automatically cancelled. ```php fn () => activity(CancelHotelActivity::class, "Hotel booked: Grand Hotel... Confirmation #902928") ``` -------------------------------- ### Start AI Conversation in Bash Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-02-07-building-a-durable-ai-travel-agent-with-laravel.md Initiates the AI-driven conversation process. This command can optionally inject failures into specific booking steps (hotel, flight, or car) for testing purposes by using the `--inject-failure` flag. ```bash php artisan app:ai ``` ```bash php artisan app:ai --inject-failure flight ``` -------------------------------- ### Register Route for Email Verification Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-29-email-verifications.md This route initiates the email verification process by creating and starting a new VerifyEmailWorkflow. Pass hashed passwords to prevent plain text storage in logs. ```php use App\Workflows\VerifyEmail\VerifyEmailWorkflow; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Route; use Workflow\WorkflowStub; Route::get('/register', function () { $workflow = WorkflowStub::make(VerifyEmailWorkflow::class); $workflow->start( 'test+1@example.com', Hash::make('password'), ); return response()->json([ 'workflow_id' => $workflow->id(), ]); }); Route::get('/verify-email', function () { $workflow = WorkflowStub::load(request('workflow_id')); $workflow->verify(); return response()->json('ok'); })->name('verify-email'); ``` -------------------------------- ### Configure Waterline UI Access Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-11-19-waterline-ui.md Define a Gate to control which users can access the Waterline UI. By default, it's only available in local environments. This example restricts access to a specific admin email. ```php Gate::define('viewWaterline', function ($user) { return in_array($user->email, [ 'admin@example.com', ]); }); ``` -------------------------------- ### Workflow with Side Effect Example Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-12-22-new-laravel-workflow-feature-side-effects.md Demonstrates using `sideEffect` to wrap non-deterministic code like random number generation. This ensures the result is deterministic within the workflow execution. Use activities for retriable, long-running tasks. ```php use Workflow\Workflow; use function Workflow\{activity, sideEffect}; class SideEffectWorkflow extends Workflow { public function execute() { $sideEffect = yield sideEffect( fn () => random_int(PHP_INT_MIN, PHP_INT_MAX) ); $badSideEffect = random_int(PHP_INT_MIN, PHP_INT_MAX); $result1 = yield activity(SimpleActivity::class, $sideEffect); $result2 = yield activity(SimpleActivity::class, $badSideEffect); if ($sideEffect !== $result1) { throw new Exception( 'These side effects should match because it was properly wrapped in sideEffect().' ); } if ($badSideEffect === $result2) { throw new Exception( 'These side effects should not match because it was not wrapped in sideEffect().' ); } } } ``` -------------------------------- ### FFmpeg Activity for Video Conversion Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-02-07-automating-qa-with-playwright-and-laravel-workflow.md This activity converts a WebM video file recorded by Playwright into MP4 format using FFmpeg. It then deletes the original WebM file and returns the path to the new MP4 file. Ensure FFmpeg is installed and accessible in the system's PATH. ```php namespace App\Workflows\Playwright; use Illuminate\Support\Facades\Process; use Workflow\Activity; class ConvertVideoActivity extends Activity { public function execute(string $webm) { $mp4 = str_replace('.webm', '.mp4', $webm); Process::run([ 'ffmpeg', '-i', $webm, '-c:v', 'libx264', '-preset', 'fast', '-crf', '23', '-c:a', 'aac', '-b:a', '128k', $mp4 ])->throw(); unlink($webm); return $mp4; } } ``` -------------------------------- ### Run Webhook Sample Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-05-08-learning-durable-workflow-from-the-sample-app.md Initiates the webhook sample workflow, which will wait for an external signal. Observe its state in Waterline. ```bash php artisan app:webhook ``` -------------------------------- ### Run AI Activity Loop Sample Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-05-08-learning-durable-workflow-from-the-sample-app.md Launches the AI activity loop sample workflow. Requires the OPENAI_API_KEY environment variable to be set for successful execution. ```bash php artisan app:ai ``` -------------------------------- ### Build Static Website Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/README.md Generates the static content for the website into the 'build' directory, ready for hosting. ```bash $ yarn build ``` -------------------------------- ### Deploy Website (SSH) Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/README.md Deploys the website using SSH. Ensure SSH is configured for your deployment target. ```bash $ USE_SSH=true yarn deploy ``` -------------------------------- ### Publish and Run Migrations Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-28-extending-laravel-workflow-to-support-spatie-laravel-tags.md Publish the migrations for both Workflow and Spatie Laravel Tags, then run them to set up the necessary database tables. ```sh php artisan vendor:publish --provider="Workflow\Providers\WorkflowServiceProvider" --tag="migrations" php artisan vendor:publish --provider="Spatie\Tags\TagsServiceProvider" --tag="tags-migrations" php artisan migrate ``` -------------------------------- ### Deploy Website (No SSH) Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/README.md Deploys the website without using SSH. Replace \ with your actual GitHub username. ```bash $ GIT_USER= yarn deploy ``` -------------------------------- ### Get Workflow Result Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Fetch the status and, if completed, the output of a Workflow. Use the workflow_id returned by `start_workflow` to check progress. Once status is `WorkflowCompletedStatus`, the output field contains the result. ```APIDOC ## POST /api/workflow/result ### Description Fetches the status and output of a specified workflow. ### Method POST ### Endpoint /api/workflow/result ### Parameters #### Request Body - **workflow_id** (string) - Required - The ID of the workflow to retrieve the result for. ### Request Example { "workflow_id": "some_workflow_id" } ### Response #### Success Response (200) - **found** (boolean) - Indicates if the workflow was found. - **workflow_id** (string) - The ID of the workflow. - **status** (string) - The current status of the workflow (e.g., 'WorkflowCompletedStatus', 'WorkflowFailedStatus'). - **running** (boolean) - Indicates if the workflow is currently running. - **output** (any) - The output of the workflow if it has completed successfully. Null otherwise. - **error** (string) - An error message if the workflow failed. Null otherwise. - **created_at** (string) - The timestamp when the workflow was created. - **updated_at** (string) - The timestamp when the workflow was last updated. #### Response Example { "found": true, "workflow_id": "some_workflow_id", "status": "WorkflowCompletedStatus", "running": false, "output": { "message": "Workflow finished successfully!" }, "error": null, "created_at": "2023-10-27T10:00:00+00:00", "updated_at": "2023-10-27T10:05:00+00:00" } ``` -------------------------------- ### Register MCP Server Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Registers the WorkflowServer with the MCP facade, making it accessible via the specified web route. This setup is crucial for enabling communication between AI clients and your workflow system. ```php use App\Mcp\Servers\WorkflowServer; use Laravel\Mcp\Facades\Mcp; Mcp::web('/mcp/workflows', WorkflowServer::class); ``` -------------------------------- ### Create Booking Tools Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-02-07-building-a-durable-ai-travel-agent-with-laravel.md Generates tool classes for booking different travel services. These tools are intended to be used by agents to gather booking details. ```bash php artisan make:tool BookHotel ``` ```bash php artisan make:tool BookFlight ``` ```bash php artisan make:tool BookRentalCar ``` -------------------------------- ### Define Loan Application Workflow with Finite Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-04-25-combining-laravel-workflow-and-state-machines.md This PHP code defines a LoanApplicationWorkflow that integrates with the Finite state machine to manage the states of a loan application. ```php use Finite\StatefulInterface; use Finite\StateMachine\StateMachine; use Finite\State\State; use Finite\State\StateInterface; use function Workflow\await; use Workflow\Models\StoredWorkflow; use Workflow\SignalMethod; use Workflow\Workflow; class LoanApplicationWorkflow extends Workflow implements StatefulInterface { private $state; private $stateMachine; public function setFiniteState($state) { $this->state = $state; } public function getFiniteState() { return $this->state; } #[SignalMethod] public function submit() { $this->stateMachine->apply('submit'); } #[SignalMethod] public function approve() { $this->stateMachine->apply('approve'); } #[SignalMethod] public function deny() { $this->stateMachine->apply('deny'); } public function isSubmitted() { return $this->stateMachine->getCurrentState()->getName() === 'submitted'; } public function isApproved() { return $this->stateMachine->getCurrentState()->getName() === 'approved'; } public function isDenied() { return $this->stateMachine->getCurrentState()->getName() === 'denied'; } public function __construct( public StoredWorkflow $storedWorkflow, ...$arguments ) { parent::__construct($storedWorkflow, $arguments); $this->stateMachine = new StateMachine(); $this->stateMachine->addState(new State('created', StateInterface::TYPE_INITIAL)); $this->stateMachine->addState('submitted'); $this->stateMachine->addState(new State('approved', StateInterface::TYPE_FINAL)); $this->stateMachine->addState(new State('denied', StateInterface::TYPE_FINAL)); $this->stateMachine->addTransition('submit', 'created', 'submitted'); $this->stateMachine->addTransition('approve', 'submitted', 'approved'); $this->stateMachine->addTransition('deny', 'submitted', 'denied'); $this->stateMachine->setObject($this); $this->stateMachine->initialize(); } public function execute() { // loan created yield await(fn () => $this->isSubmitted()); // loan submitted yield await(fn () => $this->isApproved() || $this->isDenied()); // loan approved/denied ``` -------------------------------- ### Run Elapsed Time Sample Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-05-08-learning-durable-workflow-from-the-sample-app.md Executes the sample workflow designed to measure elapsed time. This demonstrates handling time-sensitive operations without replay drift. ```bash php artisan app:elapsed ``` -------------------------------- ### Validate User Data Business Logic Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-07-10-building-reliable-agentic-loops-with-laravel-workflow-and-prismphp.md This activity validates the generated user data against specific business rules. It checks for the presence of a name and hobbies, ensures hobby details are complete, and verifies that the user's name starts with a vowel. ```php use Workflow\Activity; class ValidateUserActivity extends Activity { public function execute($user) { if (empty($user['name']) || !is_array($user['hobbies']) || count($user['hobbies']) === 0) { return false; } foreach ($user['hobbies'] as $hobby) { if (empty($hobby['name']) || empty($hobby['description'])) { return false; } } // Extra Validation: The user's name must start with a vowel. if (!in_array(strtoupper($user['name'][0]), ['A', 'E', 'I', 'O', 'U'])) { return false; } return true; } } ``` -------------------------------- ### Configure VS Code/GitHub Copilot for MCP Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Sets up the MCP client configuration for VS Code and GitHub Copilot. This JSON file defines the connection details for the Laravel workflow server, enabling AI assistants to interact with your workflows. ```json { "servers": { "laravel-workflow": { "type": "http", "url": "http://localhost/mcp/workflows" } } } ``` -------------------------------- ### BookHotel Tool Implementation Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-02-07-building-a-durable-ai-travel-agent-with-laravel.md Implements the BookHotel tool, which collects hotel booking details without performing the actual booking. Collected data is stored in a static array for later processing by the workflow. ```php class BookHotel implements Tool { public static array $pending = []; public function description(): Stringable|string { return 'Book a hotel for the user.'; } public function handle(Request $request): Stringable|string { self::$pending[] = [ 'type' => 'book_hotel', 'hotel_name' => $request['hotel_name'], 'check_in_date' => $request['check_in_date'], 'check_out_date' => $request['check_out_date'], 'guests' => (int) $request['guests'], ]; return 'Booking hotel: ' . $request['hotel_name'] . ' from ' . $request['check_in_date'] . ' to ' . $request['check_out_date'] . ' for ' . $request['guests'] . ' guest(s)'; } public function schema(JsonSchema $schema): array { return [ 'hotel_name' => $schema->string()->required()->description('The name and location of the hotel to book'), 'check_in_date' => $schema->string()->required()->description('Check-in date (YYYY-MM-DD)'), 'check_out_date' => $schema->string()->required()->description('Check-out date (YYYY-MM-DD)'), 'guests' => $schema->integer()->required()->description('Number of guests'), ]; } } ``` -------------------------------- ### Create GetWorkflowResultTool Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Generates a new tool class for fetching workflow results. This command-line instruction sets up the basic structure for the tool. ```bash php artisan make:mcp-tool GetWorkflowResultTool ``` -------------------------------- ### Implement Video Conversion Activity Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-31-converting-videos-with-ffmpeg.md An Activity that uses the PHP-FFMpeg library to convert a video file to WebM format. Includes a heartbeat mechanism to keep the activity alive during long conversions. ```php namespace App\Workflows\ConvertVideo; use FFMpeg\FFMpeg; use FFMpeg\Format\Video\WebM; use Workflow\Activity; class ConvertVideoWebmActivity extends Activity { public $timeout = 5; public function execute($input, $output) { $ffmpeg = FFMpeg::create(); $video = $ffmpeg->open($input); $format = new WebM(); $format->on('progress', fn () => $this->heartbeat()); $video->save($format, $output); } } ``` -------------------------------- ### Run Prism for LLM Generation Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-07-10-building-reliable-agentic-loops-with-laravel-workflow-and-prismphp.md Execute this command in a separate terminal to initiate the LLM generation process using Prism. ```bash php artisan app:prism ``` -------------------------------- ### Create Workflow MCP Server Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Generate a new MCP server class for managing workflows. Configure its name, version, instructions for AI clients, and the available tools. ```php namespace App\Mcp\Servers; use App\Mcp\Tools\GetWorkflowResultTool; use App\Mcp\Tools\ListWorkflowsTool; use App\Mcp\Tools\StartWorkflowTool; use Laravel\Mcp\Server; class WorkflowServer extends Server { protected string $name = 'Workflow Server'; protected string $version = '1.0.0'; protected string $instructions = <<<'MARKDOWN' This server allows you to start and monitor Workflows. ## Typical Usage Pattern 1. Call `list_workflows` to see what workflows are available. 2. Call `start_workflow` with the workflow name and arguments. 3. Store the returned `workflow_id`. 4. Call `get_workflow_result` until status is `WorkflowCompletedStatus`. 5. Read the `output` field for the result. ## Status Values - `WorkflowCreatedStatus` - Workflow has been created - `WorkflowPendingStatus` - Queued for execution - `WorkflowRunningStatus` - Currently executing - `WorkflowWaitingStatus` - Waiting (timer, signal, etc.) - `WorkflowCompletedStatus` - Finished successfully - `WorkflowFailedStatus` - Encountered an error MARKDOWN; protected array $tools = [ ListWorkflowsTool::class, StartWorkflowTool::class, GetWorkflowResultTool::class, ]; } ``` -------------------------------- ### Configure Shared Queue Connection Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Configure a shared queue connection in the `config/queue.php` file. This allows microservices to communicate through a common queue. ```php // config/queue.php 'connections' => [ 'shared' => [ 'driver' => 'redis', 'connection' => 'shared', 'queue' => env('SHARED_REDIS_QUEUE', 'default'), ], ], ``` -------------------------------- ### Define Video Conversion Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-31-converting-videos-with-ffmpeg.md Defines a Workflow that orchestrates the video conversion activity. It specifies the activity to be executed and its input/output parameters. ```php namespace App\Workflows\ConvertVideo; use function Workflow\activity; use Workflow\Workflow; class ConvertVideoWorkflow extends Workflow { public function execute() { yield activity( ConvertVideoWebmActivity::class, storage_path('app/oceans.mp4'), storage_path('app/oceans.webm'), ); } } ``` -------------------------------- ### Verify Email Activity Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-29-email-verifications.md Activity to create a new user and verify their email address. Requires email and password. ```php namespace App\Workflows\VerifyEmail; use App\Models\User; use Workflow\Activity; class VerifyEmailActivity extends Activity { public function execute($email, $password) { $user = new User(); $user->name = ''; $user->email = $email; $user->email_verified_at = now(); $user->password = $password; $user->save(); } } ``` -------------------------------- ### Publish Workflow Configuration Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-28-extending-laravel-workflow-to-support-spatie-laravel-tags.md Publish the configuration file for `laravel-workflow` to allow for customization. ```sh php artisan vendor:publish --provider="Workflow\Providers\WorkflowServiceProvider" --tag="config" ``` -------------------------------- ### Implement Travel Agent Activity Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-02-07-building-a-durable-ai-travel-agent-with-laravel.md This activity resets pending bookings, processes conversation history, and prompts the AI agent. It returns the agent's text response and any collected booking requests. ```php class TravelAgentActivity extends Activity { public function handle($messages) { BookHotel::$pending = []; BookFlight::$pending = []; BookRentalCar::$pending = []; $history = array_slice($messages, 0, -1); $currentUserMessage = end($messages); $response = (new TravelAgent()) ->continue($history) ->prompt($currentUserMessage->content); $bookings = array_merge( BookHotel::$pending, BookFlight::$pending, BookRentalCar::$pending, ); return json_encode([ 'text' => (string) $response, 'bookings' => $bookings, ]); } } ``` -------------------------------- ### Define Workflow and Activity Classes in Activity Microservice Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md In the activity microservice, define the workflow and activity classes. The activity class should contain the execute method with the business logic. Ensure connection and queue properties are set. ```php class MyWorkflow extends Workflow { public $connection = 'shared'; public $queue = 'workflow'; } class MyActivity extends Activity { public $connection = 'shared'; public $queue = 'activity'; public function execute($name) { return "Hello, {$name}!"; } } ``` -------------------------------- ### Configure Shared Database Connection Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Define a shared database connection in the `config/database.php` file. This connection will be used by multiple microservices to share data. ```php // config/database.php 'connections' => [ 'shared' => [ 'driver' => 'mysql', 'host' => env('SHARED_DB_HOST', '127.0.0.1'), 'database' => env('SHARED_DB_DATABASE', 'forge'), 'username' => env('SHARED_DB_USERNAME', 'forge'), 'password' => env('SHARED_DB_PASSWORD', ''), ], ], ``` -------------------------------- ### Set Workflow and Activity Queue Connections Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Configure the `connection` and `queue` properties for Workflow and Activity classes to use the shared queue. This directs workflow and activity tasks to the shared queue for processing. ```php // app/Workflows/MyWorkflow.php class MyWorkflow extends Workflow { public $connection = 'shared'; public $queue = 'workflow'; } ``` ```php // app/Workflows/MyActivity.php class MyActivity extends Activity { public $connection = 'shared'; public $queue = 'activity'; } ``` -------------------------------- ### Create TravelAgent Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2026-02-07-building-a-durable-ai-travel-agent-with-laravel.md Generates a new agent class for handling travel-related requests. This agent is designed to be conversational and utilize specific tools. ```bash php artisan make:agent TravelAgent ``` -------------------------------- ### Define a Basic Workflow Class Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-05-21-saga-pattern-and-laravel-workflow.md Extend the Workflow class to create a new workflow. The execute method will contain the core logic. ```php class BookingSagaWorkflow extends Workflow { public function execute() { } } ``` -------------------------------- ### Basic Workflow with Activities Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-05-21-saga-pattern-and-laravel-workflow.md This snippet shows the basic structure of a workflow that executes activities sequentially. It includes a try-catch block for error handling, representing the 'happy path' of a distributed transaction. ```php use function Workflow\activity; use Workflow\Workflow; class BookingSagaWorkflow extends Workflow { public function execute() { try { $flightId = yield activity(BookFlightActivity::class); $hotelId = yield activity(BookHotelActivity::class); $carId = yield activity(BookRentalCarActivity::class); } catch (Throwable $th) { } } } ``` -------------------------------- ### Configure Available Workflows Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-12-03-laravel-workflows-as-mcp-tools-for-ai-clients.md Defines the whitelisted workflows accessible by AI clients. Ensure `WORKFLOW_MCP_ALLOW_FQCN` is set appropriately in your environment if you need to allow fully qualified class names. ```php return [ 'allow_fqcn' => env('WORKFLOW_MCP_ALLOW_FQCN', false), 'workflows' => [ 'simple' => App\Workflows\Simple\SimpleWorkflow::class, 'prism' => App\Workflows\Prism\PrismWorkflow::class, ], ]; ``` -------------------------------- ### Convert URL to PDF Activity Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-12-06-job-chaining-vs-fan-out-fan-in.md This activity converts the content of a given URL into a PDF document using an external API. Ensure API keys and endpoint URLs are correctly configured. ```php namespace App\Workflows\BuildPDF; use Illuminate\Support\Facades\Http; use Workflow\Activity; class ConvertURLActivity extends Activity { public function execute($url) { $fileName = uniqid() . '.pdf'; Http::withHeaders([ 'Apikey' => 'YOUR-API-KEY-GOES-HERE', ]) ->withOptions([ 'sink' => storage_path($fileName), ]) ->post('https://api.cloudmersive.com/convert/web/url/to/pdf', [ 'Url' => $url, ]); return $fileName; } } ``` -------------------------------- ### Configure ClarifAI Service Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-20-ai-image-moderation-with-laravel-workflow.md Add ClarifAI service configuration to config/services.php to make credentials accessible. ```php 'clarifai' => [ 'api_key' => env('CLARIFAI_API_KEY'), 'app' => env('CLARIFAI_APP'), 'workflow' => env('CLARIFAI_WORKFLOW'), 'user' => env('CLARIFAI_USER'), ] ``` -------------------------------- ### Run Queue Workers for Microservices Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Run queue workers in each microservice to process jobs. Use the 'queue:work' Artisan command, specifying the connection and queue for both workflow and activity queues. ```sh php artisan queue:work shared --queue=workflow ``` ```sh php artisan queue:work shared --queue=activity ``` -------------------------------- ### Define Workflow and Activity Classes in Workflow Microservice Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md In the workflow microservice, define both the workflow and activity classes. The workflow class should include an execute method that yields the activity. Ensure connection and queue properties are set. ```php class MyWorkflow extends Workflow { public $connection = 'shared'; public $queue = 'workflow'; public function execute($name) { yield activity(MyActivity::class, $name); } } class MyActivity extends Activity { public $connection = 'shared'; public $queue = 'activity'; } ``` -------------------------------- ### Approve or Reject Workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-20-ai-image-moderation-with-laravel-workflow.md Loads an existing workflow by its ID and signals it to either approve or reject the moderation process. Use the appropriate method based on the desired outcome. ```php $workflow = WorkflowStub::load($id); $workflow->approve(); // or $workflow->reject(); ```