phattarachai/remote-prompt
Remote Prompt is a Laravel package for managing prompts across remote connections. It offers a simple, expressive API to define, send, and handle prompts, making it easy to add remote-driven or interactive workflows to your PHP applications with minimal setup and configuration.
remote-prompt gives you an rh binary for driving a remote Laravel host from your local machine — chiefly rh artisan (run an artisan command there) and rh put (upload a file there). Treat it as the "quick, one-off" tool you reach for between full deploys.
Minimal setup:
composer require phattarachai/remote-prompt --dev
php artisan vendor:publish --tag=remote-prompt-config # or create config/remote-prompt.php
Define at least two targets in the published config — one non-production (staging) and one production — with host, SSH user, remote project path, and PHP binary. Naming a target production is meaningful: it is what enables the red, default-no confirmation prompt.
First use case, end to end:
rh artisan staging migrate:status # read-only: runs without asking
rh artisan staging migrate --force # mutating, non-prod: prompts
rh put app/Models/User.php staging # push a single hotfix file, then:
rh artisan staging cache:clear
Look first at: the targets block in the config, rh --help, and rh artisan --help. Everything else is a thin wrapper over those two commands.
Per-environment targets, per-environment guardrails. Keep staging fully permissive and reserve the production name for the real thing. Any target not named production will not prompt, so a typo'd target name (prod, Prod, production-2) silently loses the safety prompt. Pick a naming convention and stick to it.
Script and CI usage (the v1.3.0 story). Before v1.3.0 a production write without a TTY refused outright; now it just runs. That makes this viable:
#!/usr/bin/env bash
set -euo pipefail
rh artisan production migrate --force
rh artisan production queue:restart
rh artisan now streams output as it arrives and still exits with the remote command's exit code, so set -e, && chains, and Makefile/composer-script steps behave correctly — even for a ten-minute import where you want to watch progress:
rh artisan production import:legacy --force 2>&1 | tee -a storage/logs/import.log
Deploy-adjacent hotfix flow. The common day-to-day pattern is: edit a Blade file or a model locally, rh put it to the target, then run rh artisan <target> view:clear (or config:clear) so the change takes effect without a full pipeline. Chain them in a small shell function so you never forget the clear step.
Agent / automation flow. Since non-TTY production writes now proceed, the confirmation contract has moved out of the tool and into your wrapper. Encode it explicitly:
[[ "${ALLOW_PROD:-no}" == "yes" ]] || { echo "refusing prod write"; exit 1; }
rh put app/Models/User.php production
Give an AI agent the same rule in its instructions rather than relying on the CLI to stop it.
Read-only fast path. migrate:status, route:list, about, tinker --execute style read-only commands still skip the prompt in a terminal — lean on those for triage before touching anything.
rh artisan <target> <command…> puts the target first; rh put <local-path> <target> puts it last. Muscle memory from one will bite you on the other.docker run without -t, in a cron job, or under an agent, there is no prompt at all — it proceeds. Verify your TTY assumption before assuming you're protected.rh before you upgrade, and dry-run them against staging.--force. The tool's prompt is not a substitute for artisan's own production confirmation; you will hit both gates.rh artisan into something line-oriented, output now interleaves as it is produced rather than arriving in one block — usually better, but any buffering assumption (e.g. expecting one atomic write, or stdout/stderr ordering) should be re-tested.rh put writes as the SSH user; if PHP-FPM runs as a different user, a pushed file can be unreadable or un-writable. Check permissions on the first put to each target, and prefer uploading into directories already group-writable.php artisan config:clear locally, otherwise a cached config keeps pointing at the old host/path.${REMOTE_PROD_HOST} etc. from the targets block; the config file is a natural place to leak a private key path or password into git.-v/--verbose to see the SSH command being composed — most "command not found", wrong-PHP-version, and wrong-remote-path failures become obvious when you can read the command line.How can I help you explore Laravel packages today?