protonemedia/laravel-task-runner
Laravel Task Runner lets you define reusable tasks as classes and run them from Artisan, code, or a schedule. It offers clean task registration, output handling, and cron-like scheduling for maintenance routines and background work.
Architecture fit
protonemedia/laravel-task-runner targets a specific gap in most Laravel codebases: shell logic that lives in .sh files, Makefiles, Envoy files, or copy-pasted exec() calls, outside of dependency injection, outside of tests, and outside of code review conventions. It reframes each script as a Task class whose body is a Blade template, executed through a runner abstraction that can target localhost or a configured remote host over SSH. For a TPM, the relevant architectural claim is not "we can run shell commands" — Artisan and Process already do that — it is "shell becomes a first-class, testable, reviewable artifact in the same language and repo as the application." That fits well with Laravel monoliths and mid-sized platform teams that already own their deploy/provisioning scripts but do not want to stand up Ansible, Terraform provisioners, or a full config-management discipline. It fits poorly with organizations that already have an established ops toolchain (Ansible/Puppet/Salt), a platform team that owns infrastructure-as-code separately, or a hard requirement for agent-based execution and orchestration beyond "SSH into host, run script."
Integration feasibility
Integration cost is genuinely low: composer require, publish the config, declare one or more servers (host, port, user, key material), write task classes, invoke via the facade or from an Artisan command/job. There is no schema change, no service to deploy, no daemon. The package is pure PHP on top of Composer, so it slots into existing CI without new infrastructure. The main feasibility question is not "can we install it" but "where does it run from" — an HTTP request, a queued job, a scheduled command, or a CI runner each impose very different timeout, credential, and audit constraints.
Technical risk
{{ }} escaping model is HTML-oriented, not shell-oriented. Any interpolation of user- or env-supplied values into a command string is a potential quoting bug or injection vector. This needs an explicit, enforced convention (quote-and-escape helper, or restrict to validated scalars) before the package is used with anything dynamic.max_execution_time, memory from buffered output, no retry). Whether the package gives you queue-native ergonomics — retries, backoff, locking, per-task timeouts, output streaming — determines whether it is a developer convenience or a production execution layer. Verify before committing.checkout, fetch-metadata, laravel-pint-action, git-auto-commit-action) plus adding PHP 8.5 to the test matrix. No API changes, no deprecations, no new capability, no breaking changes; the 1.x line is behaving as a stable, additive-only series. Read that as positive on hygiene and neutral on everything else — the release does not tell us anything about SSH semantics, escaping, or execution model, so none of the substantive risks move.localhost execution on Windows dev machines and non-POSIX shells is a likely rough edge; assume Linux/macOS-only for local runs.Key questions
already-ran guards), or is that entirely our convention?known_hosts handling exist, and can it be enforced rather than bypassed?TaskRunner::fake() + assert-rendered-command)? This is the package's core value proposition — if testing is weak, the justification collapses.Stack fit
Best fit: Laravel 10/11/12 monolith on PHP 8.1+, Linux hosts, existing Artisan-command culture, small platform team (1–4 people) that owns its own deploys, and no incumbent configuration-management tool. Poor fit: polyglot estates with a dedicated infra team, Kubernetes-first deployments (where kubectl exec/Jobs already cover this), or environments with strict no-SSH-from-app-tier policy.
Migration path
Adopt as a refactor of what already exists, not as a new capability. The lowest-risk first move is to port an existing .sh script verbatim into a Task::render() Blade template with no behavioral change, then diff the emitted command against the original for a set of representative inputs. That validates the escaping model and the execution semantics against real scripts before anything new is written. Keep Envoy/Deployer in place during this phase; the task runner wraps individual steps, it does not need to replace the orchestrator. Upgrading 1.6.0 → 1.7.0 is a no-op for application code; pick up 1.7.0 if the team is already on or moving to PHP 8.5, otherwise it is a patch-level bump with no behavioral surface.
Compatibility
Pin an exact minor version in composer.json — 1.7.0 is the current best pin, both for PHP 8.5 readiness and because it is the only release tested against 8.5 — and add the package's requirements to the CI matrix (PHP version, Laravel version). Confirm there is no dependency on the ssh2 PECL extension — a pure-PHP SSH implementation is strongly preferable because it removes a per-host build step and keeps CI and container images unchanged. Verify behavior against the oldest Laravel version still in support on the team, not just the newest.
Sequencing
df -h, systemctl is-active), an idempotent maintenance task, and one non-idempotent task to observe failure behavior. Confirm fake/assert helpers work.set -euo pipefail, naming, output redaction, where credentials come from, which hosts are eligible..env plaintext; define per-environment server entries; decide host-key verification policy.Maintenance Code footprint is small — a config file, a handful of task classes, and a wrapper. The recurring cost is the package itself: one maintainer, low issue volume, release cadence tied loosely to Laravel majors. 1.7.0 reinforces that the package tracks upstream PHP releases (8.5 support landed via CI matrix changes and shipped with no API impact), which is the maintenance behavior you want from a dependency this small — but it is still a one-person release train, and the dependabot-heavy changelog confirms the release volume is CI housekeeping rather than feature work. Budget a half-day per Laravel upgrade to validate compatibility, and maintain an internal fork-ready posture (the MIT license and small surface make a fork genuinely viable, which is the real mitigation for the bus-factor risk). Do not let task classes sprawl into dozens of bespoke scripts; that recreates the problem the package was adopted to solve.
Support No vendor SLA, no paid support tier. Support is GitHub issues plus internal expertise. That is acceptable for developer tooling with a documented fallback, and unacceptable for anything on the critical path of customer-facing availability. Keep the task runner off the request path of production traffic.
Scaling
SSH-per-task does not scale horizontally on its own: N hosts means N connections, N timeouts, and a partial-success matrix the package likely does not model. For fan-out, wrap in queued jobs with per-host granularity, a concurrency limit, and per-host success/failure records. Output buffering in memory means output-heavy commands (large log dumps, tar, rsync progress) should be redirected to files rather than captured. For a handful of hosts and a few dozen tasks a day, scaling is a non-issue; for fleet-wide operations, this package is the wrong tool and should be scoped to single-target or small-fan-out work.
Failure modes
{{ }} inside a task template.timeout command) as a belt-and-braces measure.Ramp-up
API surface is small enough that a Laravel developer is productive in under a day. The real ramp-up cost is on the operations side: whoever reviews these tasks needs enough shell literacy to spot an unquoted variable or a missing set -e. Plan for a short internal guild session and a conventions doc; without it, the package becomes a way to ship unreviewed bash with a PHP veneer, which is worse than the status quo.
How can I help you explore Laravel packages today?