Posted by Kyle Hankinson June 16th, 2026
GMCP (Generic MUD Communication Protocol) lets a MUD send your client structured data out of band: your health, the current room, your inventory, and more. Instead of scraping that information out of the text on screen with fragile regular expressions, you can react to the data directly and reliably.
This post covers how to fire a trigger when a GMCP value changes, and how to read the data with getGMCP.
GMCP is enabled per connection and is on by default. You can toggle it in the connection editor. Two console commands help while you work:
Prints every GMCP value the MUD has sent so far, as formatted JSON. This is the quickest way to discover what your MUD exposes and the exact key names to match against.
Re-negotiates GMCP with the server if it was turned off.
The client flattens each GMCP package into dotted paths. If the MUD sends:
Char.Vitals { "hp": 100, "maxhp": 120, "mana": 50 }
the client stores:
Char.Vitals.hp = 100
Char.Vitals.maxhp = 120
Char.Vitals.mana = 50
Nested objects keep extending the path, so Room.Info { "name": "Town Square", "exits": { "north": "101" } } becomes Room.Info.name and Room.Info.exits.north.
In the trigger editor, set the match type to "variable updated (including GMCP)". The trigger's pattern is then a GMCP path, not a regular expression, and the trigger fires whenever the value at that path changes.
For example, a trigger with the pattern:
Char.Vitals.hp
fires every time your health changes. To watch several paths with a single trigger, separate them with a pipe:
Char.Vitals.hp | Char.Vitals.mana
Matching is case-insensitive by default.
When a GMCP trigger fires, the path that changed is available as \0, and you read values with getGMCP:
getGMCP('Char.Vitals.hp') returns the single value (for example 100).getGMCP('Char.Vitals') returns an object with everything under that branch: { hp: 100, maxhp: 120, mana: 50 }.Match type variable updated (including GMCP), pattern Char.Vitals.hp:
var hp = getGMCP('Char.Vitals.hp');
var max = getGMCP('Char.Vitals.maxhp');
// Show current health in the app icon badge.
badge(hp + '/' + max);
if (max && hp / max < 0.25) {
log('Warning: health is low (' + hp + '/' + max + ')');
beep();
}
Match type variable updated (including GMCP), pattern Room.Info.name:
status('Room: ' + getGMCP('Room.Info.name'));
#gmcp first to see exactly which packages and key names your MUD sends. Field names (for example hp versus maxhp) vary between MUDs.getGMCP inside the action to read the current value and decide what to do.getGMCP and setGMCP, and the Scripts post for sharing helper functions across triggers.Posted by Kyle Hankinson June 16th, 2026
The Scripts section is where you keep reusable JavaScript. Instead of copying the same code into every trigger and alias, you write a function once in a script and pull it in wherever you need it.
Every trigger and alias runs in its own JavaScript context, so the functions you define in a script are not available everywhere automatically. You make them available by including the script.
The include function loads another script by name and makes everything it defines available to the current trigger, alias, or script. scriptName is the title of the script as it appears in the Scripts list, and is not case sensitive.
require is identical to include. Use whichever reads better to you.
A script is only ever included once per run, so it is safe to include the same script from several places, and scripts may include other scripts.
Create a script named Combat with a couple of helpers:
// Script: Combat
function herb(name) {
command('get ' + name + ' from pack');
command('eat ' + name);
}
function quaff(potion) {
command('quaff ' + potion);
}
To use it from a trigger, include the script at the top of the action, then call the function. (Capture groups from the trigger's pattern are available as \1, \2, and so on. See the Regular expression tips post.)
// Trigger action. Pattern: ^You feel hungry
include('Combat');
herb('bloodroot');
An alias works exactly the same way. Here the first capture group of the alias pattern is passed straight through:
// Alias action. Pattern: ^h (\w+)
include('Combat');
herb('\1');
Because the include runs first, herb is ready to call on the lines that follow.
When you change a script, reload so your triggers and aliases pick up the new code:
Reloads every trigger, alias, and script from disk and reports how many of each were loaded.
Combat script and a Travel script) and include only what each trigger needs.# commands.Posted by Kyle Hankinson August 17th, 2022
If you need a trigger or alias to match on a regular expression, here are some hints and tips to use.
As you type your regex, the main mud display will update to highlight matches.
\0.\1, \2, \3, etc.For whitespace (space, tab, linebreak) use the \s+ syntax option. While most muds will use spaces, some muds will use tabs is certain instances which may case a basic space match to fail.
Posted by Kyle Hankinson August 5th, 2022
Clears anything currently in the messages window.
Removes the main output buffer.
Displays a list of current autocomplete entries.
Clears the autocomplete entries.
Displays a list of current script variables.
Disconnects from the current session. If auto-reconnect is enabled, a countdown will be started and the connection re-attempted.
Disconnects the current connection and closes the window.
Sets the specified varaible to the specified value.
Stops any activly waiting scripts. Scripts may be in a waiting state from either a wait or a commandAndReadFromServer function.
Enables a trigger or alias by name (not case sensitive) and saves the change.
Disables a trigger or alias by name (not case sensitive) and saves the change.
Shows whether the named trigger or alias is currently enabled or disabled.
Reloads all triggers, aliases, and scripts from disk and reports how many of each were loaded. Run this after editing a script so your triggers and aliases pick up the new code.
Creates or updates an alias, mapping name to command, and saves it.
Resumes any scripts that are paused in a wait.
Prints all current GMCP values as formatted JSON, handy when writing GMCP-aware scripts.
Posted by Kyle Hankinson August 4th, 2022
The command function will process a command as if the user had typed it into the console. Any aliases in the command will be processed as well.
The wait function will cause the current script to delay for timeout seconds before continuing the script. The wait timeout can contain miliseconds by specifying decials.
The log function will append the specific message to the console. This can be useful when debugging scripts.
The processForAutocomplete method adds entries to the interal autocomplete list. entries can either be an array of strings, or a string which will be delimited by whitespace.
The commandAndReadFromServer will process a command as if the user had typed it into the console, then will read from the server until the next data stream has finished.
The beep function will cause your device to output a beep sound effect.
The addComm function adds message to the Communications (Messages) window, the side panel used to collect tells, says, and other channel chatter.
Variable functions are unrelated to javascript functions. Rather they are a way to store variables over multiple scripts. Regular javascript variables are removed from memory once the funcion has completed. All varaible methods below should have variable names passed as a string.
The isEmpty method returns true if a variable is unset or empty. A string variable is considered empty if it has zero length or is completely whitespace. A numeric variable is never empty (zero is not considered empty). Use the unset function to completely unset a variable.
The unset function is used to completely clear a variable.
Stores value under variableName for the rest of the session, so other scripts can read it back with getVar.
Returns the current value of the specific variable.
(getValue is an alias for getVar, and setValue for setVar.)
The status function updates the status bar to show the value for display.
The notify function will add a macOS notification with the specific message.
The badge method updates the app icon badge to show the specific display. This should be limited to a short string (less than 10 characters), or it will be truncated. Current/max HP is an example of what one might display in the badge.
Returns the GMCP value stored at the dotted path, for example getGMCP('Char.Vitals.hp'). If path points at a branch rather than a single value (for example getGMCP('Char.Vitals')), an object containing everything under that branch is returned.
Sets the GMCP value at the dotted path. Useful for feeding your own data into GMCP-aware overlays and scripts.
The setVar/getVar variables above live only for the current session. To keep a value across launches, use the saved variants.
Stores value on disk under name so it survives quitting and relaunching the app.
Returns the value previously stored with saveVar, or nothing if it was never set.
Waits until the condition function returns true, checking repeatedly, and gives up after timeout seconds (default 5). Returns true if the condition was met, or false if it timed out.
Stops any other actions that were already running when this one started. Handy when several triggers could fire at once and you only want the first to proceed.
Releases scripts that are paused in a wait. Pass an action name to release a specific one, or call it with no argument to release all.
Collapses rapid repeats. Returns true the first time it is called for name, then false for any call within delay seconds. Use it to act on only the first of a burst of matching lines.
Rate-limits by key. Returns 0 when the action is allowed to run, or the number of seconds remaining until it is allowed again.
Rate-limits a function: calls fn at most once per interval seconds (the first call always runs, calls in between are skipped). Unlike throttle, you hand it the function and it does the gating for you.
Returns the number of seconds since you last pressed Enter in the input field. Useful for telling whether you are actively playing or idle.
Creates or updates an alias at runtime, mapping name to command.
Loads a script from the Scripts section so its functions are available in the current trigger, alias, or script. See the Scripts post for a full walkthrough.