Skip to content
Synchronize issues assigned to you from a Github repo into Things.
Objective-C Roff Shell Other
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Synchronize issues assigned to you, one-way, from a Github repo into Things.



ThingsHub checks for a config file at ~/.thingshubconfig, then traverses from the home directory down to the current dir (or from the root to the current dir, if the current directory isn't in ~), merging in .thingshubconfig files as it finds them.

This means you can put global configuration and defaults (eg. githubLogin, tagNamespace) in ~/.thingshubconfig, leaving project-specific settings (eg. repoOwner, repoName, areaName, projectPrefix) in your-project-dir/.thingshubconfig, sort of like using git's configuration system.

Configuration parameters may additionally be specified on the command line, like -githubLogin cdzombak. Parameters specified on the command line override those found in any configuration files.

See thingshubconfig.example in this distribution for details on the configuration format.

You may also want to add .thingshubconfig to your ~/.gitignore.

Run with the -verbose flag to see the final, resolved configuration.


These may be used in a configuration file (param = value) or on the CLI (-param value).

  • githubLogin: your Github username. Required.
  • tagNamespace: namespace to use as a prefix for tags imported from Github. Optional; default is "github".
  • delegate: the sync delegate used to communicate with the local task manager app. Optional; default is Things. Currently only Things is supported.
  • map.label name (-"map.label name" on the CLI, if you need spaces): map a Github label to a local tag name. Optional.
  • repoOwner: the owner of the Github repo to sync. Required.
  • repoName: the Github repo to sync. Required.
  • areaName: the area in Things to use for this project. Optional; default is none.
  • projectPrefix: prefix which will be applied to project names & tasks’ titles (before the issue number). Optional; default is none.


The simplest usage is just to run thingshub and specify all configuration options on the command line.

Alternatively, run thingshub from a project's directory, optionally specifying configuration options via the CLI. ThingsHub will configure itself from your configuration files as described in the Configuration section.

Logout/Reset Github OAuth Token

thingshub -logout <GitHub Username>

Version Check

thingshub -version


Current version: v1.1.1.

Installation requires Xcode.

Get the most recent release and run make install. This will install thingshub to /usr/local/bin and its man page to /usr/local/share/man/man1.


Ensure that the target directories exist and you can write to them.


  • This never updates GitHub from Things; GitHub is the source of truth.
  • This will always create issues in Anytime. You can move them to Today/Upcoming/Someday as desired.
  • This will move issues to areas/projects to reflect milestone changes. This doesn't change the todo between Today/Anytime/Upcoming/Someday.

Why one way sync? Why GitHub as the source of truth?

  • Issues may be modified by many people online, increasing the chance of conflicts if you modify an issue locally.
    • Conflict management is easy this way, and we probably won't lose much data.
  • Issues are often closed as side effects of other operations (merges, commits), so closing issues in your client usually won't make much sense.
  • Descriptions on Todos are often used in your task management software for personal notes.
  • The entire one-way sync operation is idempotent, so partial sync failures are easily recoverable; just re-trigger the sync.

Sync (to Things)

  • Milestones, if any, are represented as projects in your selected Area, or if no Area, as projects in Anytime/Someday. Projects' due dates reflect the milestone due date.
  • Milestones: each project's due date, tags, and status are updated every sync. Name and notes are only touched when creating a new Project.
  • A project is not created for an open milestone if you have no issues assigned to you in that milestone.
  • Issues without a milestone are placed directly in the selected Area, or if no Area, into Anytime. (If updating an existing task, we won't move it back into Anytime, though.)
  • Todos and projects are marked as incomplete/complete based on open/close status in Github. Todos/projects that exist for deleted/unassigned milestones/issues are marked as canceled.
  • We only search for existing issues in Today, Anytime, Upcoming, Someday, Projects, and Trash — not Inbox or Logbook.
  • We don't touch due dates or handle scheduling for tasks.
  • Issues: todo's project/area, tags, name, and status are updated every sync. Notes are only touched when the todo is created.
  • Pull requests are treated the same as issues, with "(PR #xxx)" instead of just "(#xxx)" in the name.


  • When a todo is created/updated, remove any extant "github:" tags, and apply "github:" tags that are currently on the issue.
  • When creating/updating a todo/project, add a "via:github" tag.


Thanks to:


MIT; see LICENSE in this distribution.

Dev Notes

  • Run make bootstrap to set up a local, self-contained environment for CocoaPods. Its only external dependency is Bundler.
  • make pods runs bundle exec pod install for you.

Implementation details


Identifying synced items:

The following will be placed in the notes field for relevant projects/todos:

  • //thingshub/ORG/REPO/issue/###//
  • //thingshub/ORG/REPO/milestone/###//

Reference Material

Things and Scripting Bridge


Github API

KVC, Predicates


You can’t perform that action at this time.