Ubuntu Accomplishments Spec
One of the core reasons why people participate in Open Source projects is so they can create something that helps the project and showcase their contributions to that project. While we provide plenty of opportunities for people to contribute, we don’t provide a good way of contributors articulating their contributions well.
About the best method of doing this today is Launchpad Karma, but this (a) does not cover many different types of contributions (namely, those outside Launchpad), (b) has been criticized over how the scoring is performed, and (c) is uninteresting to visualize -- it is just a set of numbers.
This spec is inspired by accomplishments systems used in other systems such as the Sony Playstation 3 trophies, StackExchange Badges, and FitBit Badges. The goal here is to create an accomplishments system that is extensible enough to be used by by local applications on a computer and contributions made to the Ubuntu community. In performing this work, these are some core goals:
Extensible - this system should be flexible enough that accomplishments at a desktop level (e.g. “Sent Email From Thunderbird” or “Sent First Tweet In Gwibber”) can be achieved, as well as project contributions (e.g. “Filed First Bug”).
Discoverable - the user should be able to see what trophies are available and find out how to achieve them.
Highly Distributed - the solution should be as de-centralized as possible so as to reduce the need for an extensive central service.
Integrated - the solution should be tightly integrated into Ubuntu itself and not just a series of disconnected web-pages.
Throughout the rest of this document we will use the following terms:
Accomplishment - a goal or objective that can be achieved.
Trophy - a representation of an achieved accomplishment.
Validation Server - a component in the workflow that ensures that trophies are legitimately earned.
The workflow presented here was developed between Stuart Langridge and Jono Bacon and achieves each of the core goals highlighted above. The solution is highly distributed, uses Ubuntu One as a data sharing mechanism, and would be integrated into the Unity experience.
With this proposed system there are two core types of accomplishments:
Local Accomplishments - accomplishments that are local to your specific computer and do not require verification elsewhere (e.g. completing a level in a game).
Global Accomplishments - accomplishments that require verification from a third party (e.g. filing your first bug in Ubuntu).
All accomplishments are representing using the same kind of format and schema, but local and global accomplishments differ in how they generate trophies.
Accomplishments are defined by an application by storing a .accomplishment file in the system folder /usr/share/accomplishments/accomplishments/app-name.
Trophies, which are a record that a specific user has accomplished a particular accomplishment, are stored in a user-specific folder $XDG_DATA_HOME/accomplishments (this is likely to be $HOME/.local/share/accomplishments on most Ubuntu installations).
Local Trophies - $XDG_DATA_HOME/accomplishments/local/app-name/accomplishment-name.trophy
Global Trophies - $XDG_DATA_HOME/accomplishments/global/app-name/accomplishment-name.trophy
For local accomplishments (e.g. completing a level on a game on your system), the following files are involved:
.accomplishment - this file outlines some cosmetic details about the accomplishment such as the name (e.g. ‘Level 2 Completed’), an icon (e.g. ‘level2.png’) and what other accomplishments should be completed before this one can be unlocked (e.g. ‘mygame/level1complete’).
.trophy - this file is the generated trophy that represents the completed accomplishment. libaccomplishments-daemon generates it.
Here the .accomplishment file describes the accomplishment and when that accomplishment occurs (e.g. in a game you complete Level 2) the app would call the accomplishments system to process the .accomplishment file and generate the .trophy. This trophy would be added to the Ubuntu One Share for the local trophies.
For Global Accomplishments we need to poll external services to check if an accomplishment has been achieved (e.g. Filing Your First Bug in Launchpad). To perform this polling we need the following:
A logic file (for global accomplishments) - a file that contains the logic for determining if an accomplishment has been achieved (e.g. for a ‘1st Bug Filed’ accomplishment this file could be a small Python script that connects to Launchpad to see if you have filed a bug yet).
A server logic file (for global accomplishments) - a server-side file that verifies that the accomplishment has genuinely been completed.
A key needs-signing - true in the .accomplishment file
The logic file is a script named similarly to the accomplishment and stored in /usr/share/accomplishments/scripts. So if an app installs a global accomplishment /usr/share/accomplishments/accomplishments/ubuntu-community/first-bug.accomplishment, there should be a corresponding script /usr/share/accomplishments/scripts/ubuntu-community/first-bug.py where the extension of the script can be anything. (The identifying part is ubuntu-community/first-bug.)
At regular intervals, the libaccomplishments system will look to see, for each user on the system, which global accomplishments they have not yet accomplished. For each accomplishment, the system then runs the corresponding logic script. A logic script is expected to exit with a specific exit code: 0 for “the accomplishment is now accomplished”, 1 for “the accomplishment is not yet accomplished”, and 2 for “there was an error”. (FIXME: what should we do if there’s an error? How do we notify the user?) If the logic script indicates that the accomplishment was successfully accomplished, the system creates the appropriate .trophy file. However, because this is a global accomplishment, it needs to be validated by a separate service to ensure the user isn’t faking it. As such, this separate hosted service would have the server-side logic file for each respective accomplishment available to users.
These are the tools that will process these files and provide the functionality:
libaccomplishments-daemon - the server which provides the base-level D-Bus API to query and award accomplishments, and also notifies the user with notify-osd when an accomplishment is accomplished. The daemon should be started by D-Bus activation on the session bus if it is not already started
libaccomplishments - a small library that is called by a local application (e.g. a game) that wants to generate a trophy for a completed accomplishment; a wrapper around the libaccomplishments-daemon D-Bus API
libaccomplishments-daemon-scriptrunner - a small root-level script that runs all the available accomplishment logic files once a day and generates trophies to be sent to the validation server
accom-validate - a tool on the validation server that processes new trophy requests and signs valid trophies.
Local Accomplishment Workflow
Here is how the workflow would work for an application that is local on the computer (e.g. completing a level in a game). Note that in this case that the trophy is never sent to a validation server, this all happens locally and the logic that determines that an accomplishment has been achieved is conducted inside the application.