Documentation
MusterConnecting your apps
Updated
A monitor needs something to check in. There are two ways to do it:
- A Laravel application installs the
artisan-build/muster-clientpackage. Every scheduled command then reports to Muster automatically and registers its own monitor on its first run. - Anything else, such as a shell script, a cron job on another server or an app in another language, sends a plain heartbeat to a monitor you created by hand.
Muster is not a Scalpels provider, so Scalpels does not attach applications to it and the Attach to an existing app flow does not apply. You connect each application yourself, from that application.
Check-in tokens
Every check-in is authenticated with a bearer token sent in an Authorization: Bearer … header. Muster grants two permissions:
| Permission | Allows |
|---|---|
muster.check-in |
Reporting a scheduled run, and sending heartbeats. |
muster.history.read |
Reading a monitor's event history over HTTP. |
A token is bound to exactly one permission and one Muster installation. A check-in token cannot read history, and a token issued by one Muster is useless against another.
Today Muster issues only muster.check-in tokens, and the supported way to get one is the client package's muster:install command, below. There is currently no supported way to obtain a muster.history.read token, so the history route cannot be called yet; read a monitor's history in the web UI, or through the MCP tools.
The Laravel client
The client subscribes to Laravel's own scheduler events, so you change none of your command definitions.
Install the package
The package requires PHP 8.3 or newer and Laravel 13. It is built inside the Muster repository at packages/muster-client and is not yet published on Packagist, so composer require artisan-build/muster-client on its own cannot find it. Your fork of Muster contains the package. Until it is published, install it from a checkout of your fork with a Composer path repository:
composer config repositories.muster-client path /absolute/path/to/muster/packages/muster-client
composer require artisan-build/muster-client:@dev
A path repository only resolves where that directory exists, which matters for any environment that runs composer install from your lock file.
Connect it
From the application, run:
php artisan muster:install --url=https://<your-muster-url>/api/schedule-events
php artisan config:clear
If you leave off --url, the command asks for it. It must be the full schedule-event endpoint, ending in /api/schedule-events.
The command starts a temporary listener on 127.0.0.1, prints an authorization URL and opens it in your browser. Sign in to Muster, check that the page is asking for the muster.check-in permission, and approve it within three minutes. The exchange completes locally and the token is never printed. After confirming, the command writes MUSTER_URL and MUSTER_TOKEN to the application's .env and reports Muster connection settings updated. If authorization fails, the .env file is left unchanged.
muster:install --manual-token prompts for a pre-issued token with hidden input instead of using the browser. A generic credential minted with bfc:credential:mint is not interchangeable with the token the browser ceremony issues. Do not pass a real token with --token: command arguments can end up in shell history and process listings.
The package does nothing at all unless both MUSTER_URL and MUSTER_TOKEN are set and non-empty. Set only one and it logs a warning. If MUSTER_URL is not https, it logs a warning that the token is travelling in plaintext.
What it reports
- When a scheduled command starts, the client sends a
startedevent with a unique execution id. The first one registers the monitor, already enabled, named after the command, with its real cron expression and timezone. - A foreground command reports
finishedwith its exit code and runtime when it completes. - A command run in the background reports when its background process finishes.
- Non-zero exits and thrown failures are reported as failures.
- Runs skipped by a filter or by overlap prevention are reported as skips, never as failures or missed runs.
Reporting fails open, with short timeouts (half a second to connect, one second in total by default). If Muster is unreachable, your command still runs; the failure is logged at debug level only. The client never reads, sends or logs command output.
Only scheduled runs are reported. Running a command by hand with php artisan reports nothing, and the application's own scheduler has to be running.
Verify the connection
Run the application's scheduler, or wait for its next scheduled run. In Muster, /monitors should show a new monitor for each command that ran, which you did not create, with its cron expression in the list. Its page shows the command, expression and timezone, and started and finished events in its activity history.
A plain heartbeat
For anything that is not a Laravel scheduled command, create a monitor by hand (see Monitors), note its id, and have the task send one request when it finishes:
curl -sS -X POST https://<your-muster-url>/api/monitors/<id>/check-ins \
-H "Authorization: Bearer $MUSTER_TOKEN"
The request takes a muster.check-in token, such as the one muster:install wrote to a connected application's .env. Load it into the environment rather than typing it on a command line, where it would land in your shell history.
A successful check-in answers {"status":"ok"}. The monitor goes healthy and its next due time moves forward by its cadence. If it was missed, Muster records a recovered event and sends the recovery alert.
A missing or wrong token, a token for another installation, an unknown monitor id or a disabled monitor all answer 401 with {"message":"Unauthenticated."}.
Put the request at the end of the script you want watched, so it only runs when the work succeeded, and give the monitor a cadence and grace period that suit how often the script runs.