Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Tidier cleans up old GitHub issues and pull requests. By default, Tidier looks for issues and pull requests that have the label waiting on response, and closes them with a friendly comment if no activity has occurred for 90 days. This allows you to leave behind bug reports that were never followed up, without needing to aggressively close issues ahead of time.


This is a standard Python app. Install the dependencies in Pipfile.lock, then run You will probably want to do this in a cron job or something similar. I would recommend creating a free Heroku app and installing the Scheduler addon. Then you can set Tidier's environment variables (see below) as Config Vars.


Configuration is done through environment variables.

  • TIDIER_ACCESS_TOKEN (Mandatory) Personal access token for the GitHub API. Needs the public_repo scope at least, and possibly repo if you want Tidier to manage your private repositories also.
  • TIDIER_FOR_REAL (Defaults to disabled) Unless this variable is set, Tidier will do a dry run and tell you what it would close, if anything.
  • TIDIER_LABEL (Defaults to waiting on response) The label used to identify issues and pull requests that should be closed.
  • TIDIER_INCLUDE_REPOS (Defaults to including everything) Regex that repository names (e.g. raxod502/straight.el) must match to be considered.
  • TIDIER_EXCLUDE_REPOS (Defaults to excluding nothing) Regex that repository names must not match to be considered.
  • TIDIER_NUM_DAYS (Defaults to 90) Number of days of inactivity after which issues and pull requests will be closed.
  • TIDIER_COMMENT_FORMAT (See below) Template for comment that is posted.
  • TIDIER_WEBHOOK (Defaults to none) URL to which to send an HTTP request after Tidier finishes. For example, this allows you to integrate with Dead Man's Snitch for error reporting.

Comment format

The default TIDIER_COMMENT_FORMAT (with newlines added for readability) is:

This thread is being closed automatically by
[Tidier]( because it is labeled with
"{label}" and has not seen any activity for {num_days} days. But don't
worry—if you have any information that might advance the discussion,
leave a comment and the thread may be reopened :)

This is run through Python's str.format, so it can use the {label} and {num_days} templates. Then the comment will be interpreted by GitHub as Markdown.


Tidier uses the GitHub API v3. First, it performs a search for all open issues with the label you specify. That means Tidier will run faster if you use a less popular label. Then, Tidier retrieves a list of all the repositories to which you have explicit access, and uses this to prune the search results. Next, Tidier checks whether you are a collaborator on the remaining repositories, so that it can skip ones where you do not permission to close issues. (At this stage, Tidier also applies the regexes you may have provided in TIDIER_INCLUDE_REPOS and TIDIER_EXCLUDE_REPOS.) Finally, Tidier iterates through the issues by repository, checking if their "last updated" time is too long ago.

See also

I previously used NO CARRIER, until it broke one too many times. The problems with NO CARRIER are manifold: it has an order of magnitude more lines of code than it needs to have (~1,100 versus ~200); it is written in overengineered spaghetti-Scala; the build system is byzantine (compare here, here, here versus this project); and it lacks facilities for either customizing the comment format (see open issue) or iterating over all your repositories. Hence this project, which replaces it entirely.


📡 Tidies up your GitHub repositories.



No releases published


No packages published