Command-line and gem client for Asana (unofficial)

Using library

See docs

Using CLI

$ checkoff --help
    checkoff - Command-line client for Asana (unofficial)

    checkoff [global options] command [command options] [arguments...]

    --help - Show this message

    help     - Shows a list of commands or help for one command
    mv       - Move tasks from one section to another within a project
    quickadd - Add a short task to Asana
    view     - Output representation of Asana tasks

Let's say we have a project like this:

project screenshot from

Checkoff outputs things in JSON. 'jq' is a great tool to use in combination:

$ checkoff view 'Personal Projects' 'Create demo'
{"":[{"name":"This is a task that doesn't belong to any sections."}],"Write it:":[{"name":"Write something"}],"Publish to github:":[{"name":"git push!"}],"Make sure it looks OK!:":[{"name":"Looks it up in your browser..."}]}
$ checkoff view 'Personal Projects' 'Create demo' | jq
  "": [
      "name": "This is a task that doesn't belong to any sections."
  "Write it:": [
      "name": "Write something"
  "Publish to github:": [
      "name": "git push!"
  "Make sure it looks OK!:": [
      "name": "Looks it up in your browser..."

You can drill down into a section on the command line:

$ checkoff view 'Personal Projects' 'Create demo' 'Publish to github:'
[{"name":"git push!"}]

You can use fun jq tricks:

$ checkoff view 'Personal Projects' 'Create demo' | jq 'to_entries | map(.value) | flatten | map(.name)'
  "This is a task that doesn't belong to any sections.",
  "Write something",
  "git push!",
  "Looks it up in your browser..."

And even gather counts for project metrics:

$ checkoff view 'Personal Projects' 'Create demo' | jq 'to_entries | map(.value) | flatten | map(.name) | length'

Naming things

Since checkoff looks up things by their name, if you have two things with the same name, you're probably going to have a bad time.


Note that I don't know of a way through the Asana API to target individual sections and pull back only those tasks, which is a real bummer! As a result, sometimes the number of tasks brought back to answer a query is really large and takes a while--especially if you're querying on something like :my_tasks_today. To help make that less annoying, I do caching using memcached; you'll need to install it.

If you're working in real time with modifications in Asana, you may need to occasionally run echo 'flush_all' | nc localhost 11211 to clear the cache.


This will work under OS X:

brew install memcached
ln -sfv /usr/local/opt/memcached/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist
gem install checkoff


You'll need to create a file called .asana.yml in your home directory, that looks like this:


# when you click on 'My Tasks' in Asana, put the number (just the
# number) from the URL in the mapping below.
  'Your workspace name here': 'some_long_number'


# Click on your profile in the uppper right in Asana, go to 'My
# Profile Settings', click on 'Apps', got o 'Manage Developer Apps',
# and select 'Create New Personal Access Token'.  Note down the key
# in this section.
personal_access_token: 'some_big_long_string_from_asana.com_here'

Alternately you can set environment variables to match - e.g., ASANA__PERSONAL_ACCESS_TOKEN


This project, as with all others, rests on the shoulders of a broad ecosystem supported by many volunteers doing thankless work, along with specific contributors.

In particular I'd like to call out:

  • Audrey Roy Greenfeld for the cookiecutter tool and associated examples, which keep my many projects building with shared boilerplate with a minimum of fuss.