Writing Alfred Workflows in Go

Recently I’ve been really enjoying programming and especially programming Alfred workflows in Go language.

It’s super fun programming things that you immediately use yourself and can later iterate on at your own will.

Getting started with Alfred

In short, Alfred is an extendable launcher that can search through almost anything you want it to search through. Be it files, your Safari or Chrome bookmarks, documentation, notes and a lot lot more. You can also issue commands to it such as opening a specific application, quitting an app, uploading images to Imgur and again, a lot lot more. The limit to what you can do is your imagination and what it is you are trying to achieve.

I have mentioned that Alfred is an extendable launcher. And you can extend it with workflows which other users have made and some of which they have shared. In order for you to install these workflows you will need to buy the powerpack upgrade, which in my opinion is well worth the money for what you will get out of it.

Assuming you have done that, you can take a look at the official Alfred resources on how to get started with Alfred. If you ever wish to get help with whatever you are trying to make and searching it online or going through the Alfred documentation does not help, feel free to ask your question on the Alfred Forum. Where you can both ask questions or share the workflows which you will soon be able to create.

Creating workflows with Go

I personally really love developing workflows with Go language and that is what I will focus on in this article but you can create workflows in any language. Many times you might not even need a programming language at all as Alfred provides many objects that you can use already to glue things together such as opening URLs, filtering through a list of items, opening files and a lot more.

To ease my time in developing these workflows, I use a really awesome library called AwGo. Here I will try to describe how you can get started developing workflows in Go using this library and what my workflow is like using it.

To install the library, you first have to have Go installed on your system which you can do here. If you never tried writing Go, you can complete Go Tour and read through How to Write Go Code and Effective Go. Once you do that, you can install AwGo library using this command:

go get github.com/deanishe/awgo

Awesome. Now that you have the library, let’s make our first workflow.

In our case we want to create a simple workflow that would replace Alfred's native Web Search that can be found here:

So that it can be curated and extended by the community of people.

So let’s make it. Create a directory with name alfred-web-searches and in there we can create our first file main.go. I usually put all my Alfred workflows I am working on inside ~/src/alfred directory. Now here comes the most awesome part and what makes developing workflows in Go pure joy. We can symlink our project with code to an actual Alfred workflow and then build our code into a single binary file that we can then call from our Alfred launcher. To do that we will need a small command line utility that you can install by running this command in your shell:

go get -u github.com/jason0x43/go-alfred/alfred

Now you have a global CLI tool named alfred that you can use. For more information on what this command can do, you can read its docs. But you will really need only 3 commands from it.

Assuming you have installed the command, let’s get it to use. To use it, we first need to create a directory named workflow in our Go project. So the structure of our project will simply be:

├── main.go

└── workflow

Now we will need to create our Alfred workflow in Alfred Preferences, give it the name that we want, in our case, Web Searches, a unique Bundle ID and an optional image. In the end it may look something like this:

In order to symlink our Go project to Alfred, we will need to carry a few files to the workflow directory we created earlier. To do that, right click on the workflow in the side bar and open it in Finder:

You will find two files there. Info.plist and our .png image file. To quickly carry these files to our workflow directory I usually use the Move to... file action on these files and simply choose the workflow folder to move the selected files there.

Sweet. Now that we have done that, we can delete the workflow we made in Alfred Preferences. We can then cd into our alfred-web-searches or if we are already there we can run alfred link command that will make a symlink between our workflow directory and the Alfred directory.

Now let’s write some code. 🦄

Writing the workflow

I love using VS Code for writing Go code because of its awesome Go plugin and the amazing vim emulation but you can choose any editor you like.

Let’s first take a step back and look at what we will be making. We will make a workflow that will read a file that will contain a bunch of search queries and arguments. The arguments will represent the names of the searches like Google search or Reddit search and the searches will be the actual searches to these websites. Similar to how you add Web Searches in Alfred where you replace the search query with {query} here we will do the same.

AwGo library we installed earlier will take care of everything Alfred related. Generating the JSON that Alfred actually reads to show us our results together with updating our workflow.

Before we go further, it is best to at least skim read through AwGo documentation. It is very detailed and it also has examples.

The way our workflow works is that we will have a CSV file that will contain the names of all the searches that you can make. In our case all the entries in this CSV file will be of this format:

name-of-search,search-query

Which in practice looks like this:

g: GitHub,https://GitHub.com/search?utf8=✓&q={query}&type=

The thing before the comma is the name of the search and the thing after is the search query where {query} will be replaced by what the user will type in Alfred.

The g: is a prefix that is useful to signify the theme of the search.Where g: stands for GitHub.

It’s good practice to separate code into appropriate files. Where main.go is always the starting point of Go programs. So let’s create this file.

Here is the code we need to get the necessary setup for this workflow to work:

I find it good practice to keep the main.go file as minimal as possible and do the majority of the work in other files. Do note that repo variable on line 20 links to a GitHub repository that is already made on GitHub. This is only needed if you want to publish the workflow on GitHub and have auto updating work.

One of the files that all my Go workflows have is update.go which holds the necessary functions needed to make auto updating work inside the workflow. Putting these functions inside update.go file and calling showUpdateStatus() in places where you want to check for update is all that is needed. AwGo does all the work for us so we can just focus on what we want the workflow to do.

I then create the file where I will do the needed actions for searching the CSV file that we will have. I called it search.go and inside it I have this code:

This code simply reads the CSV file named websites.csv that is placed inside the Alfred workflow and sends the searches and the queries you make on them to Alfred.

So let’s create this websites.csv file inside our workflow directory and put some searches in there. Like these two:

w: Twitter,https://twitter.com/search?q={query}&src=typd
w: Letterboxd,http://letterboxd.com/search/{query}

Which will make searches to Twitter and Letteboxd websites respectively.

To compile and run our program from Alfred we can run alfred build in the root directory of our project. Since we have linked our workflow before with alfred link, running this command will build the binary and put it into our workflow directory which in turn will show up in Alfred Preferences with the name we gave our workflow earlier. If you followed the steps so far, and ran alfred build, you will find this workflow show up in your Alfred Preferences:

Awesome. We are really close now to see our workflow magic in action. Let’s try and call our binary file. To do that we will need to create Alfred script filter. And in there we call our binary with our search argument. Here is how your script filter should look:

The "$1" in the end represent's the user's input. And now one last thing. We need to give our workflow a version number since we want to keep track of the changes we make to the workflow and make our auto updating work. To do that click on this button on the top:

And then add your version here:

Semantic versioning is required.

And we’re done. 🎊

Almost. Now let’s attach a hotkey trigger to call our script filter and assign a hotkey we like like ⌥ + L. And finally press our hotkey. If all worked well, you should see Alfred prompt greet us with:

Now let’s try and add one more search query there and edit our websites.csv file. For example I love searching Reddit a lot so let’s add it:

w: Reddit,https://www.reddit.com/search?q={query}&sort=relevance&t=all

Now let's run alfred build again from our project root directory. And then press ⌥ + L or whatever shortcut you set again.

That was fast right? Well that’s all there really is to it. You change your code in your project, run alfred build and then run the binary file you built in any way you want from Alfred. Plus you get to use all the various Alfred objects that come builtin to Alfred to enhance your workflow.

Also, it’s best we make a new friend. In the top right corner in Alfred Preferences you will see a bug:

This is Alfred’s debugger and it is incredibly useful. It will essentially be your new home as you develop your workflows because it will allow you to see the output of your commands as well as show you errors that happened that were not caught by your editor and whatever you decide to log to it.

It is best to change Log from Interesting Information to All information here:

So you don’t miss anything. Try and run you workflow again and see what happens. It should show you something like this:

The part after [input.scriptfilter] { is what Alfred gets to process to show us the results. And before that you get some information and you can decide what to show there. Perhaps you want to log some variable or keep track of some changes or debug problems. This is the place to see what is happening with your program.

There is one more awesome thing that you can do if you do use VS Code as your editor like I do. You can assign a VS Code task that will run alfred build for you so you won't ever have to go to your terminal to repeatedly run the command. If you do wish to create such a task, read through the docs on how to create and set default tasks here, then put this into tasks.json:

{
"version": "2.0.0",
"tasks": [
{
"label": "alfred build",
"type": "shell",
"command": "alfred build",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

And assign alfred build as your default task. I then assign ⌘ + O to run my default task in Keyboard Shortcuts:

So my workflow then becomes:

  1. Change code.
  2. Save (check if no compiler errors).
  3. ⌘ + O (builds the binary).
  4. Call the binary from Alfred.
  5. Check the debugger for issues if there is any.
  6. Repeat.

Extending the workflow with Alfred objects

We are really close now to complete our workflow. Now when we press return on any of our Alfred results, two variables will be saved and can be used from Alfred, ARG and URL where ARG holds the name of the search being made and URL holds the URL that will be searched.

We want to make the search on the chosen in Alfred website. We can create a Keyword object to give us a prompt of what search do we actually want to make on the chosen website. In the Keyword object we can write this:

The Title is there to show where the search is going to be made. {var:ARG} is Alfred's way of expanding variables. It will expand to Quora in our case. and {query} is the user's query that will be typed out in the Keyword object itself. Assuming the user has typed his query. We can then attach our Keyword to Script Filter like so:

The only thing left now is to replace the query that the user has typed in this keyword with the {query} that is in the our URLs. We can do that using Bash with a simple replace. Let's create a Bash script (there is a Bash script object we can use and inside let's put the line that will do this replacement for us:

echo -n ${URL/\{query\}/$1}

Attach that to our Keyword trigger and finally to finish this all off, let’s add a Open URL action to actually make our search and simply pass in our result from the bash script there which will be {query}.

All together it should look like this:

Now try running our workflow again and hopefully see the magic at play.

The most awesome thing is that now we can share our workflow open source on GitHub together with our websites.csv file so anyone on Earth can extend and add more websites you can search from.

Releasing the workflow

Releasing our made workflow is then really easy too. Assuming we made the changes we wanted, created our GitHub repository and pushed the code there. Running alfred pack will create .alfredoworkflow zip file that you can then attach to your release in GitHub. Just don't forget to give proper versions to your Releases and update the versions of the workflow in Alfred itself.

Wrapping up

I hope this article was helpful and gave you an idea how fun developing workflows for Alfred in Go can be and how seamless the

Write code -> Save -> Build -> Run from Alfred

cycle can be.

It’s incredibly satisfying seeing your code working and solving some problem of yours.

Oh and and this workflow we built together. Sadly it already exists. So you will have to go on and make something else. Fortunately there is infinitely many other things you can do, now that you have the power to do it, don’t be afraid to build it and ask questions.

As for the workflow, it can be found and downloaded from GitHub and it has over 500 searches that you can search from. And of course this list can be extended by community.

Don’t be afraid to build and share the things you’ve built.

If you enjoyed reading this, give it a 👏. And look into other articles I wrote. You can support me on Patreon and get updates on next articles I write on Twitter.💜