spatie/scotty
Scotty is a beautiful SSH task runner. Write tasks as plain bash in a Scotty.sh file with annotation comments, and it connects to your remote servers, runs each script, and shows exactly what's happening. Fully compatible with Laravel Envoy.
Architecture fit. Scotty is a single-file PHP phar that behaves as a developer-facing CLI, not a library. That distinction drives the whole evaluation: there is no composer require inside an application, no service provider, no container binding, no programmatic API, and no runtime surface inside the Laravel app it deploys. "Integration" here means inserting a binary into the deploy and runbook workflow. For a Laravel/PHP shop this is a clean fit — the tool speaks the team's language (Composer distribution, Artisan commands inside tasks, PHP-backed Blade hooks) while remaining entirely stateless: no agent, no daemon, no control plane, no state to reconcile. The blast radius of adoption is one file plus one script in the repo.
Integration feasibility. High, and unusually cheap to approve. Three install paths exist (curl the phar into the repo, drop it on $PATH, or composer global require spatie/scotty), each clearing a security review faster than any hosted platform requiring an installed agent and a contract. The Scotty.sh format is plain bash plus annotation comments (@servers, @task, @macro, @option), so there is no DSL to learn and editors highlight it for free. The claimed drop-in compatibility with Laravel Envoy — including Blade parsing ported from Envoy — makes an existing Envoy.blade.php a candidate for a near-mechanical swap rather than a rewrite. The hard prerequisite: whatever executes Scotty must already hold SSH credentials to the targets. Scotty does not solve secrets distribution, key rotation, or least-privilege access — it inherits whatever posture you already have.
Technical risk. Four items a TPM should track explicitly:
@option is unavailable there, so the two formats are not at parity — a genuine adoption wrinkle, not a footnote.@before, @after, @error, @success, @finished) that previously failed silently. That is a meaningful reliability signal for a young 1.x tool — verify hook behavior explicitly in the pilot rather than assuming it.Key questions to answer before committing:
Scotty.sh or Envoy.blade.php? Committing to one avoids the parity surprises above.--continue and --summary change semantics; pick a default per environment.Stack fit. Strongest for a Laravel/PHP monolith on a small fleet (roughly 1–10 hosts) deployed over SSH, where the team already reads bash and already has Composer and SSH keys in its toolchain. Weaker for polyglot or Windows-first teams. Structurally wrong for anyone whose real requirement is a managed pipeline with approvals, audit trails, artifact promotion, and centralized secrets — Scotty is not that, and buying it as a substitute is the expensive mistake.
Migration path. Frame this as a reversible, low-cost experiment rather than a modernization project; that framing is what makes approval easy and keeps the sunk-cost risk near zero.
chmod +x, confirm ./scotty list. Reproduce one non-critical task (cache clear, queue restart).scotty doctor first, always. It validates connectivity and macro references up front, converting a class of "it broke mid-incident" failures into a pre-flight check.--pretend against the full deploy macro. The dry-run output is the review artifact for the team that has to trust it.Envoy.blade.php. Keep Envoy installed in parallel through the overlap window, run both against staging, and diff observed effects rather than trusting "drop-in compatible" on faith. Test @before/@after/@error/@finished hooks explicitly — their prior silent failure is the highest-risk unknown.--summary. Pass/fail-only output is the CI-shaped mode; reserve verbose human output for local and incident use.Compatibility. The self-contained phar means no PHP extension or runtime dependency negotiation — a real procurement advantage (PHP itself must be present wherever the phar runs). Nested macro resolution landed in 1.3.0, custom SSH ports (host:port) and self-update in 1.4.0 — pin to 1.4.x or later if you need any of these, and to 1.4.4+ if you depend on Blade hooks. Blade-format users should verify @option availability themselves instead of assuming bash-format parity.
Sequencing. Local pilot → doctor/--pretend dry run → staging parity check against Envoy → CI adoption → incident-runbook adoption → production deploy. Deliberately sequence the incident-response use cases (--pretend, --continue, timestamped failure messages) after routine deploys are proven; they are higher-stakes and less forgiving of surprises.
Maintenance. Very low and largely self-inflicted. There is no server component, no database, no state, and nothing to patch on a schedule — the artifact is one file. Ongoing costs are the Scotty.sh script itself (reviewable like application code), periodic phar bumps (self-update support exists, but pin a version in CI for reproducibility), and the discipline of keeping the script in version control alongside the app it deploys. Total ongoing effort is best modeled as a fraction of one engineer, mostly during initial authorship.
Support. Support burden splits cleanly. Tier 1 — "the script is wrong" — is internal and debuggable because tasks are plain bash run over SSH with readable output; the team owns it, which is a feature, not a gap. Tier 2 — "the tool is wrong" — routes to Spatie's GitHub with no SLA and no commercial support path. That is acceptable for internal deploy tooling and unacceptable if it ever gates a customer-facing release without a fallback. Mitigate by keeping the Envoy scripts intact until two clean production deploys have passed, so the fallback is always one revert away.
Scaling. Scales down gracefully and up poorly. Ten hosts is fine; fifty-plus hosts, parallel fan-out requirements, staged canaries, or coordinated multi-region rollouts are where a purpose-built pipeline wins and Scotty's in-place, sequential-by-default model becomes a bottleneck. Also note the human scaling dimension: because scripts are bash and reviewed like code, contribution scales with team bash literacy, not with tooling features. Plan to revisit the tool choice at the point where release coordination — not command execution — becomes the constraint.
Failure modes to instrument:
--continue vs. abort semantics per environment and document it; this is the failure mode most likely to page someone.Ramp-up. Short for anyone comfortable with bash and SSH: an experienced Laravel engineer is productive on a simple task within roughly half a day, using the README example and ./scotty list. Full macro-and-hook fluency takes about a week of real use. The Blade/Envoy path adds a small increment for teams already familiar with Envoy. The real onboarding risk is not the syntax — it is the mental model correction: Scotty is a remote command runner, not a deployment platform. Teaching that distinction explicitly at kickoff is the single highest-leverage enablement activity, and it prevents the scope-mismatch disappointment that otherwise shows up as an unfair "the tool didn't do what we needed" verdict three months in.
How can I help you explore Laravel packages today?