### Install dependencies and start local development server Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/README.md Installs dependencies and starts the local development server. Requires Node.js 24 and npm. ```bash npm ci npm run start ``` -------------------------------- ### Start the 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 Use docker compose to build and start the app and worker services. Then run two artisan commands in separate terminals to start the queue worker and run the main workflow. ```bash docker compose up -d --build --wait app worker ``` ```bash # terminal 1 php artisan queue:work # terminal 2 php artisan app:workflow ``` -------------------------------- ### 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 app and start the queue worker. The first command initializes the app, and the second starts the queue worker to process jobs. ```bash php artisan app:init php artisan queue:work ``` -------------------------------- ### Run the Workflow with Workflow\WorkflowStub in PHP Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Shows how to create and start a workflow instance, wait for it to finish, and get its output. The expected output is commented as 'Hello, world!'. ```php use Workflow\WorkflowStub; $workflow = WorkflowStub::make(MyWorkflow::class); $workflow->start('world'); while ($workflow->running()); $workflow->output(); // Output: 'Hello, world!' ``` -------------------------------- ### Start the workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-31-converting-videos-with-ffmpeg.md Starts the ConvertVideoWorkflow by creating a workflow stub and calling start(). ```php WorkflowStub::make(ConvertVideoWorkflow::class)->start(); ``` -------------------------------- ### Install dependencies and run tests Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/src/pages/compare/temporal.mdx Installs dependencies and runs the test script that checks registration, activity scheduling and execution, and replay with a recorded activity result. ```sh composer install php test.php ``` -------------------------------- ### Install Laravel Workflow and Finite with Composer Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-04-25-combining-laravel-workflow-and-state-machines.md Install the Laravel Workflow and Finite packages via Composer. Run these commands in your Laravel project root. ```bash composer require laravel-workflow/laravel-workflow ``` ```bash composer require yohang/finite ``` -------------------------------- ### Install Waterline with Composer and Artisan Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-11-19-waterline-ui.md Install the Waterline package and publish its assets. After running these commands, the /waterline URL becomes available in your app, but only in local environments by default. ```bash composer require durable-workflow/waterline php artisan waterline:publish ``` -------------------------------- ### 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 Installs both the laravel-workflow and spatie/laravel-tags packages via Composer. ```sh composer require laravel-workflow/laravel-workflow spatie/laravel-tags ``` -------------------------------- ### Run LoanApplicationWorkflow with submit and approve signals Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-04-25-combining-laravel-workflow-and-state-machines.md Creates a LoanApplicationWorkflow instance, starts it, sends submit and approve signals with delays, then retrieves the output, which is "approved". ```php // create workflow $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" ``` -------------------------------- ### Install Laravel MCP and Publish AI Routes 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 the AI routes configuration, which creates routes/ai.php for registering the MCP server. ```bash composer require laravel/mcp php artisan vendor:publish --tag=ai-routes ``` -------------------------------- ### Run the webhook 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 a workflow that pauses on 'ready'. A signal sent from another terminal advances it to Completed, visible in Waterline. ```bash php artisan app:webhook ``` -------------------------------- ### Publish Migrations for Workflow and Spatie 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 Publishes the migration files for both packages. Run these commands after installation. ```sh php artisan vendor:publish --provider="Workflow\Providers\WorkflowServiceProvider" --tag="migrations" php artisan vendor:publish --provider="Spatie\Tags\TagsServiceProvider" --tag="tags-migrations" ``` -------------------------------- ### Create, Tag, Retrieve, and Run a Workflow 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 Console command that creates a workflow, tags it with 'tag1', retrieves it by tag, starts it, waits until it finishes, and outputs the result. ```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()); } } ``` -------------------------------- ### 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 Creates a new workflow instance using WorkflowStub::make and starts it with the 'tmp/good.jpg' argument. Use this to initiate the image moderation process. ```php $workflow = WorkflowStub::make(ImageModerationWorkflow::class); $workflow->start('tmp/good.jpg'); ``` -------------------------------- ### StartWorkflowTool PHP class 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 Full implementation of the StartWorkflowTool MCP tool. It validates input, resolves the workflow class from config, starts the workflow asynchronously, and returns the workflow ID and status. The schema method defines the tool's input parameters. ```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.'), ]; } } ``` -------------------------------- ### Configure available workflows in config/workflow_mcp.php 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 configuration file whitelists which workflows AI clients can start. It includes an 'allow_fqcn' flag and a 'workflows' array mapping keys to workflow classes. This prevents arbitrary class execution. ```php return [ 'allow_fqcn' => env('WORKFLOW_MCP_ALLOW_FQCN', false), 'workflows' => [ 'simple' => App\Workflows\Simple\SimpleWorkflow::class, 'prism' => App\Workflows\Prism\PrismWorkflow::class, ], ]; ``` -------------------------------- ### Define viewWaterline Gate for Waterline 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 access to the Waterline UI. This example allows only the user with email admin@example.com to view the UI, and must be added to the WaterlineServiceProvider to take effect outside local environments. ```php Gate::define('viewWaterline', function ($user) { return in_array($user->email, [ 'admin@example.com', ]); }); ``` -------------------------------- ### Define API routes for email verification workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-29-email-verifications.md Defines two API routes for the email verification workflow. The `/register` route creates and starts a `VerifyEmailWorkflow` with an email and a hashed password, returning the workflow ID. The `/verify-email` route loads the workflow by ID and calls the `verify()` signal method. ```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'); ``` -------------------------------- ### Build static site and validate links Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/README.md Builds the static site and validates links, matching the CI process. ```bash npm run build ``` -------------------------------- ### 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 Runs the migrations to create the necessary database tables for both packages. ```sh php artisan migrate ``` -------------------------------- ### Create booking tools with artisan make:tool 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 Run these artisan commands to generate the BookHotel, BookFlight, and BookRentalCar tool classes. These tools will be used by the agent for booking operations. ```bash php artisan make:tool BookHotel ``` ```bash php artisan make:tool BookFlight ``` ```bash php artisan make:tool BookRentalCar ``` -------------------------------- ### Create TravelAgent with artisan make:agent 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 Run this artisan command to generate the TravelAgent class skeleton. This is the first step in setting up the conversational agent. ```bash php artisan make:agent TravelAgent ``` -------------------------------- ### Run queue workers for shared queues Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Starts queue workers for the shared connection, listening to the 'workflow' and 'activity' queues. Run these in each microservice. ```bash php artisan queue:work shared --queue=workflow php artisan queue:work shared --queue=activity ``` -------------------------------- ### Create ListWorkflowsTool with artisan make:mcp-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 Run this artisan command to generate a new MCP tool class. The command is part of the Laravel MCP package setup. ```bash php artisan make:mcp-tool ListWorkflowsTool ``` -------------------------------- ### Laravel console command to run Playwright workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-02-07-automating-qa-with-playwright-and-laravel-workflow.md Defines the 'app:playwright' artisan command. It creates and starts the CheckConsoleErrorsWorkflow, waits for it to finish, and prints the resulting MP4 file path. ```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']); } } ``` -------------------------------- ### Validate user business rules in ValidateUserActivity 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 Activity that returns false if name is empty, hobbies is not an array or is empty, any hobby lacks a name or description, or the name does not start with a vowel (A, E, I, O, U). Returns true only when all checks pass. ```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; } } ``` -------------------------------- ### LoanApplicationWorkflow with Finite State Machine Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-04-25-combining-laravel-workflow-and-state-machines.md Defines a LoanApplicationWorkflow that combines Laravel Workflow with Finite. It implements StatefulInterface, uses #[SignalMethod] for submit/approve/deny, and configures a Finite state machine with created, submitted, approved, and denied states. The execute method uses await to pause until signals are applied and returns the final state name. ```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 return $this->stateMachine->getCurrentState()->getName(); } } ``` -------------------------------- ### CheckImageDateActivity: Get image timestamp via HEAD request Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-11-15-invalidating-cloud-images.md This activity performs a HEAD request to the Cloud Image URL and returns the 'date' header, which represents the cached image's timestamp. It is used to determine if the image has been invalidated. ```php namespace App\Workflows\InvalidateCache; use Illuminate\Support\Facades\Http; use Workflow\Activity; class CheckImageDateActivity extends Activity { public function execute($url) { return Http::head('https://' . config('services.cloudimage.token') . '.cloudimg.io/' . $url) ->header('date'); } } ``` -------------------------------- ### Configure WorkflowServer MCP Server with Instructions and Tools 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 WorkflowServer MCP server with instructions for AI clients on how to use the three tools: list_workflows, start_workflow, and get_workflow_result. The instructions include the typical usage pattern and the list of workflow status values. ```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, ]; } ``` -------------------------------- ### Generate StartWorkflowTool with artisan make:mcp-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 Run this artisan command to scaffold a new MCP tool class named StartWorkflowTool. ```bash php artisan make:mcp-tool StartWorkflowTool ``` -------------------------------- ### InvalidateCacheWorkflow: Orchestrate cache invalidation with retries Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-11-15-invalidating-cloud-images.md This workflow coordinates the two activities: it gets the old timestamp, invalidates the cache, then waits 30 seconds and checks the timestamp up to three times. If the timestamp hasn't changed after three attempts, it restarts the invalidation process. ```php namespace App\Workflows\InvalidateCache; use Workflow\Workflow; use function Workflow\{activity, timer}; class InvalidateCacheWorkflow extends Workflow { public function execute($url) { $oldDate = yield activity(CheckImageDateActivity::class, $url); while (true) { yield activity(InvalidateCacheActivity::class, $url); for ($i = 0; $i < 3; ++$i) { yield timer(30); $newDate = yield activity(CheckImageDateActivity::class, $url); if ($oldDate !== $newDate) return; } } } } ``` -------------------------------- ### BookHotel tool class implementing Tool interface 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 Tool interface for booking hotels. The handle() method stores booking details in a static $pending array and returns a confirmation message; it does not perform the actual booking. The schema() method defines the required parameters for the AI agent. ```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'), ]; } } ``` -------------------------------- ### VerifyEmailActivity creates and verifies user Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2022-10-29-email-verifications.md Creates a new user with the provided email and password, sets email_verified_at to now, and saves the user. This activity is triggered after the user clicks the verification link. ```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(); } } ``` -------------------------------- ### Create an Activity with Workflow\Activity in PHP Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Defines an activity class that extends Activity and contains the actual logic. The execute method here returns a greeting string using the passed name. ```php use Workflow\Activity; class MyActivity extends Activity { public function execute($name) { return "Hello, {$name}!"; } } ``` -------------------------------- ### Run Prism app 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 this command in a second terminal to execute the Prism app. You will see the queue working and eventually see the validated output. ```bash php artisan app:prism ``` -------------------------------- ### Create BookingSagaWorkflow class Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-05-21-saga-pattern-and-laravel-workflow.md Defines the initial skeleton for the BookingSagaWorkflow class that extends the Workflow base class. The execute method is currently empty and will be filled with booking steps. ```php class BookingSagaWorkflow extends Workflow { public function execute() { } } ``` -------------------------------- ### Configure shared database connection in config/database.php Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2023-08-18-microservice-communication-with-laravel-workflow.md Adds a 'shared' MySQL connection to config/database.php for cross-service communication. Uses environment variables with defaults for host, database, username, and password. ```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', ''), ], ], ``` -------------------------------- ### Expected output from worker and client Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/src/pages/compare/temporal.mdx Expected output from the worker and client when run against a local Server at http://localhost:8080 with its documented development token. ```json {"greeting":"Hello, Ada!"} ``` -------------------------------- ### Run Playwright workflow Source: https://github.com/durable-workflow/durable-workflow.github.io/blob/main/blog/2025-02-07-automating-qa-with-playwright-and-laravel-workflow.md Run this command in a second terminal to execute the Playwright workflow. It captures console errors, records a video, and converts it to MP4, saving the video in the videos folder. ```bash php artisan app:playwright ``` -------------------------------- ### Create MCP Server with Artisan Command 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 named WorkflowServer using the Laravel MCP artisan command. ```bash php artisan make:mcp-server WorkflowServer ```