API

Serenade exposes an API that enables you to write your own custom commands. Custom commands are written via JavaScript files in your ~/.serenade/scripts directory.

Getting Started

Let’s take a look at a few examples of custom commands. Create a new file called ~/.serenade/scripts/make.js with the contents:

serenade.global().command("make", async api => {
    await api.focus("terminal");
    await api.typeText("make clean && make");
    await api.pressKey("return");
});

With this script, saying make from any application will open up a terminal app, type the bash command make clean && make, and then execute it.

Each script in the ~/.serenade/scripts directory will have access to an object called serenade that serves as the entry point for the API. The global method specifies that we’d like this command to be triggerable from any application. The command method takes two arguments: the voice trigger for the command, followed by an asynchronous function to execute. An api instance is passed to your async function, which enables you to automate a workflow. Inside of that function, we’re using the await keyword to make sure that each operation completes before moving onto the next. Don’t forget to mark your function with the async keyword!

If you have any syntax errors in your script, they’ll be displayed in the Serenade app.

Here’s another example. Create a new file called ~/.serenade/scripts/find.js with the contents:

serenade.app("chrome").command("find <text>", async (api, text) => {
    await api.pressKey("f", ["command"]);
    await api.typeText(text);
});

With this script, saying find hello when Google Chrome is in the foreground will open a find dialog (via pressing ⌘-f) and type the text hello into that dialog.

This time, rather than specifying global(), we used .app("chrome") to make this command valid only when Google Chrome is focused. Adding <text> to the end of the voice trigger indicates that this command is a text command, which means that anything you say after find will be passed to your function via the text argument.

Here’s one more example. Create a new file called ~/.serenade/scripts/unit.js with the contents:

serenade.global().text("test <text>", "def test_<text>(self):");

Rather than using the command method, we can instead use the text to simply map a string to another string. With this command, saying test hello will type the text def test_hello(self): into the currently-focused application.

You can create as many scripts as you want—everything in ~/.serenade/scripts will be loaded when Serenade starts up. You can also define as many commands as you’d like in each JavaScript file.

API Reference

class Serenade()

Methods to create new Builder objects with either a global scope or scoped to a single application. You can access an instance of this class via the serenade global in any script.

global()
Returns

A new Builder with a global scope. Any commands registered with the builder will be valid regardless of which application is focused.

app(application)
Arguments
  • application (string) – Application to scope commands to.

Returns

A new Builder scoped to the given application. Any commands registered with the builder will only be valid when the given application is in the foreground.

class Builder()

Methods to register new voice commands.

command(trigger, callback)

Register a new voice command.

Arguments
  • trigger (string) – Voice trigger for this command.

  • callback – Function to be executed when the specified trigger is heard.

Returns

The same Builder instance, so commands can be chained.

key(trigger, key[, modifiers)

Shortcut for the command method if you just want to map a voice trigger to a keypress. This method is equivalent to serenade.command("foo", async api => { api.pressKey(key, modifiers); });

Arguments
  • trigger (string) – Voice trigger for this command.

  • key (string) – Key to press. See Keys.

  • modifiers (string[]) – Modifier keys (e.g., “command” or “alt”) to hold down when pressing key. See Keys.

Returns

The same Builder instance, so commands can be chained.

text(trigger, text)

Shortcut for the command method if you just want to map a voice trigger to typing a string. This method is a shortcut for serenade.command("foo", async api => { api.typeText(text); });

Arguments
  • trigger (string) – Voice trigger for this command.

  • text (string) – Text to type.

Returns

The same Builder instance, so commands can be chained.

class API()

Methods for workflow automation. An instance of API is passed as the first argument to the callback passed to the command method on a Builder.

focus(app)

Bring an application to the foreground.

Arguments
  • app (string) – Application to focus.

Returns

Promise that will be resolved when the specified application has come into focus.

pressKey(key[, modifiers)

Press a key, potentially with modifier keys held down.

Arguments
  • key (string) – Key to press. See Keys.

  • modifiers (string[]) – Modifier keys (e.g., “command” or “alt”) to hold down when pressing key. See Keys.

Returns

Promise that will be resolved after the given key has been pressed.

runCommand(text)

Execute a Serenade command. For instance, you could run the command next method when you say the word go.

Arguments
  • text (string) – Text of the Serenade command to run.

Returns

Promise that will be resolved after the command is finished.

typeText(text)

Type some text.

Arguments
  • text (string) – Text to type.

Returns

Promise that will be resolved after the text has been input.

wait(timeout)

Pause execution for a fixed amount of time.

Arguments
  • timeout (number) – Amount of time to wait, in milliseconds.

Returns

Promise that will be resolved after the given number of milliseconds.

Keys

Below is a list of supported keys:

  • alt

  • backspace

  • caps

  • command

  • control

  • delete

  • down

  • end

  • escape

  • home

  • left

  • meta

  • pagedown

  • pageup

  • return

  • right

  • shift

  • space

  • tab

  • up