AccomplishmentsSpec

Go back to the accomplishments main page.

Ubuntu Accomplishments Spec

Introduction

JonoBacon: this is an idea I had a while back (the basic concept was originally proposed by Kees Cook last August, and it got discussed by Jorge, Daniel, and others on OMG Ubuntu and other places) and discussed with StuartLangridge when he was staying at my house. We fleshed out some different aspects of how the system could work and then discussed it further with DanielHolbach.

I originally wrote up this spec in a separate document for ease of editing, but wanted to present it here to invite community input but to also see if anyone is interested in working on an implementation of the idea. If you are interested, please let me know at jono AT ubuntu DOT com, particularly if you are a Python programmer who would be interested in writing some code to implement the idea.

I have registered https://blueprints.launchpad.net/ubuntu/+spec/community-p-ubuntu-accomplishments-and-trophies to discuss the idea so far at UDS in Orlando.

Overview

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.

Workflow

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.

Local Workflow

Global Accomplishment Workflow

There are two types of global accomplishments:

  • Machine Verifiable - these are accomplishments that involve third party services (e.g. Launchpad) that we can automate in verifying if they were successfully accomplished (e.g. filing your first bug or your 1000th bug comment).

  • Human Issued - these are accomplishments that cannot be auto-generated or verified but require human intervention or nomination (e.g. awards for great work in LoCo teams).

Here is the workflow for machine verifiable accomplishments. In this no user interaction is required, and here is an example applied to an accomplishment for fixing a first bug.

Machine Verifiable Workflow

Note that we still need to define our accomplishments (.accom/.logic/.logic-valid files) and ensure they are installed on the local system. These would be present in a package that makes available all possible accomplishments.

Human Issued Workflow

This workflow applies to accomplishments that are issued by someone who is trusted in the project. Examples of this could include governors (e.g. Community Council, Technical Board) or trusted members of the project (e.g. leaders of approved LoCo Teams).

This workflow requires one additional component: a web site that acts as a means for someone to assign the trophy to a user.

This website would like this this:

Web UI

This is the workflow of how the trophy is generated:

Web Workflow

When a new human issued trophy is created it should have the date attached to it (to allow multiple trophies to be issued). As an example if Joe. S. CoreDeveloper gives out a Kudos Trophy to Colin Watson on the 2nd September 2011 it will generate a trophy called Joe S. CoreDeveloper Kudos - 2nd September 2011 and this will appear in Colin Watson’s trophy cabinet. The comments field is required so that we can provide contextual information if required in visualizing the trophy (e.g. hovering over a trophy and showing the comment in a toolip)

Operating System Integration

Focusing specifically on how we deliver Ubuntu Community orientated accomplishments, the functionality would broken out across the following packages:

  • ubuntu-accomplishments - this package would contain the applications required to operate the Ubuntu Accomplishments system. Namely, libaccomplishments, libaccomplishments-daemon, libaccomplishments-daemon-scriptrunner and accom-validate.

  • ubuntu-accomplishments-community - this package contains a full set of accomplishments for participating in the Ubuntu community.

  • ubuntu-accomplishments-community-valid (ONLY FOR THE VALIDATION SERVER) - this is the companion package to ubuntu-accommplishments-community that contains a similar set of scripts that can validate accomplishments.

  • ubuntu-accomplishments-community-valid-human (ONLY FOR THE VALIDATION SERVER) - this package contains a set of human accomplishments for the Ubuntu community.

Visualizing Trophies

The visualization part of this vision is a key piece in making it successful. There are some implicit goals here:

  • Trophies should feel real - we don’t want trophies to feel like pictures on a website; they need to feel like real accomplishments that are part of your Ubuntu experience.

  • New trophies should be discoverable - trophies that you have not achieved yet should be (a) available to see so you can see what future trophies you could achieve and (b) inform the user of how to achieve those trophies.

  • You should be able to ‘unlock’ new trophies - some trophies don’t make sense unless you achieve something else first (e.g. ‘Fixed 5 Bugs’ should not be available until you have achieved ‘Fixed First Bug’). By unlocking trophies when others are completed, this will continue to grow the opportunity for new challenges throughout the system.

The designs here are preliminary designs that have not yet had Design Team input. As such, we would want to consult the design team to get their perspective on how this should.

These designs show an Accomplishments Lens that would be part of the Unity dash and which also hands out control to a helper app called the Ubuntu Trophy Cabinet.

The lens would look like this:

Lens

Here you can see the list of already accomplished trophies (these would have unique trophy icons for each one, the stars here are just because Balsamiq does not have a trophy icon Smile :-) ).

You can see here the available trophies that have not yet been accomplished. If you click on a trophy the Ubuntu Trophy Cabinet helper app is loaded.

When the user clicks on a trophy there are two outcomes (1) the user has not yet registered in the accomplishments system or (2) they have already registered.

If they have not registered they see the getting started screen:

Helper App

This screen explains the accomplishments system and allows the user to register to participate. This involves the following steps:

  1. This step creates an Ubuntu share and registers it with the validation server.
  2. This step asks the user to create a Launchpad account or authenticate. The user will need to use the same email to register in LP as in Ubuntu One. This needs to be documented. (FAQ!)
  3. A first trophy to get started with (this step should be hidden if the user has clicked on a trophy to see in the lens, this step should only appear if they load the helper app directly).

If the user has already registered with the system, they see details for how to achieve the selected trophy.

Helper App

This provides (1) a summary of the trophy (2) links to online resources where you can find help for the topics covered by this trophy and (3) an overview of what you need to do to accomplish the trophy.

The key point about the documentation here is that it is focused on the trophy and very instructive and prescriptive about the expectations of how you accomplish the trophy and what steps are involved.

If you click the My Trophies button you can see the current achieved trophies:

Helper App

This list of trophies also includes a filtering facilities to select between the context (e.g. Ubuntu Community) and topics within that context (e.g. QA). The default view here would be ‘Show me [All] trophies from [All Topics]’ and show all trophies.

Clicking the Opportunities button will show a similar view for unaccomplished trophies that are still available to be achieved:

Helper App

Clicking each of these potential accomplishments will then display the trophy information screen presented earlier.

Many of the potential bug achievements are not shown here because they require these accomplishments to be completed first. As an example, if the user completed the ‘Fixed First Bug’ accomplishment the following notify-osd bubble would appear:

Notification Bubble

If the user starts the Ubuntu Trophy Cabinet helper app directly (not by clicking on something in the lens) they will see the following:

Helper App

(the above needs more work)

Visualizing On The Web

An important component when dealing with accomplishments is allowing users to show them off. A natural place to do this is on the web.

To do this the user should switch this functionality on. To do this they would use the Accomplishments panel in the Ubuntu Control Center and enable a ‘Publish My Trophies Online’ button that will do the following:

  • The validation server knows about the global trophies (as it signs them), but not the local trophies, so the local trophies folder will be marked as a share and synced to the U1 filesync service.

The GPG public key is also shipped in the package the user installs, so the signatures can be double-checked. We took into consideration that if the key should change we would have to get the new key through the SRU process, but it’s quite unlikely that’s ever going to happen.

  • Inside the trophies folder a file called PUBLISHME will be added. This indicates the trophies have permission for publishing.
  • The user would go to trophies.ubuntu.com/<username> (e.g. trophies.ubuntu.com/jonobacon) and these are possible outcomes:

    • No share - this user is not sharing their accomplishments so nothing is shown.
    • PUBLISHME is available - if the PUBLISHME file is present the trophies are rendered.

No PUBLISHME is available - if the share is available (which it will be all trophy collectors) but there is no PUBLISHME file, the content will not be published as the user has not given permission.

Configuration File Schemata

Configuration files are all ini-style, as parseable by Python’s ConfigParser.RawConfigParser.

.accomplishment (Machine Verifiable)

ITEM

TYPE

EXAMPLE

PURPOSE

name

string

name = Level 1 Completed

Summary of the accomplishment.

icon

string

icon = /path/to/level1.png

A standard icon for the accomplishment.

hide

bool

hide = true

Should the accomplishment be hidden from display in the lens/helper app (used for mystery trophies in the future).

description

string

description = foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar

Longer description of how to accomplish the accomplishment.

depends

string

depends =

A list of accomplishments that must be achieved to unlock this accomplishment.

.accomplishment (Human Issued)

Differences to Machine Verifiable shown in bold.

ITEM

TYPE

EXAMPLE

PURPOSE

name

string

name = Level 1 Completed

Summary of the accomplishment.

icon

string

icon = /path/to/level1.png

A standard icon for the accomplishment.

group

string

group=ubuntu-developers

Which Launchpad group(s) can issue this accomplishment.

hide

bool

hide = true

Should the accomplishment be hidden from display in the lens/helper app (used for mystery trophies in the future).

description

string

description = foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar

Longer description of how to accomplish the accomplishment.

depends

string

depends =

A list of accomplishments that must be achieved to unlock this accomplishment.

Note that when querying for accomplishments via libaccomplishments-daemon, some keys will be returned which are not stored in the file itself (for example, “accomplished” and “locked”).

logic

This file contains executable code that is run to determine if the given accomplishment has been successful. The goal of the script is to produce a YES or NO outcome to whether the accomplishment was success.

This could be written in any language and the exit code determines success or not.

  • exit 0 - accomplishment achieved
  • exit 1 - accomplishment not yet achieved
  • exit 2 - there was an error in the script

The logic script may assume that it has access to the user’s session (for example, to make D-Bus calls).

server-side logic

Very similar to the logic file but run on the validation server and needs to be passed the user (as the user on the validation server is independent).

.trophy

A trophy file is a copy of the .accomplishment file with some extra keys:

ITEM

TYPE

EXAMPLE

PURPOSE

title

string

Machine: “Created Launchpad Account” -- Human: “Jono Bacon Kudos - 2nd September 2011”

The name of the trophy (human issued include a date so multiple trophies of the same type can be awarded).

application

string

App: “worldofgoo” -- Project: “ubuntucommunity”

What the trophy applies to.

issuer

string

Machine: “ubuntucommunity” -- Human: “dholbach”

Who gives out the trophy (machine automated just say the Ubuntu Community gave them out).

comments

string

Machine: “Created a Launchpad account.” Human: “<personal message for reason for the trophy>”.

To describe the trophy.

Draft Implementation

A draft implementation of most of this is available at lp:~sil/+junk/libaccom-draft/. These notes below are in reference to that branch.

libaccomplishments-daemon contains daemon.py and scriptrunner.py. daemon.py is the main daemon which provides the D-Bus API and does all the work. This is what should be started by D-Bus activation in a live system. scriptrunner.py is the script runner, which runs the logic files for installed accomplishments and awards the user appropriately based on the exit codes of those scripts; if run as root, it does this for all valid logged-in users.

libaccomplishments is a wrong thing; what it should be is a GObject-introspection wrapper around the libaccomplishments-daemon D-Bus API, similar to libindicate. What it actually is is a tiny Python library which is only usable from Python. This is obviously wrong but it proves the point, and someone who can actually write C or Vala can build a proper libaccomplishments.

Note that since the script runner is designed to run as root, from cron or similar, it needs a security audit! It can run as the user, but it’s not clear how to schedule this for an individual user; an individual user has a crontab, but how does the call to this script get into that crontab? Installing the libaccomplishments package happens as root, not as a user, so it’s unknown which process would add a call to the scriptrunner to a user crontab. Hence why it’s a root process which can be installed in cron.daily or similar.

demo-app is a tiny application which combines two things: an accomplishments browser (like the Unity lens mentioned above) and a standard app which knows how to award accomplishments (like a game). It uses libaccomplishments to do its work.

The daemon is capable of being told where its files (trophies, accomplishments, etc) live, rather than defaulting to the standard paths mentioned above. This is useful for testing; examples/demo.sh shows this by starting the daemon with paths pointing into the examples/ directory, and then starting the demo-app. Running this examples/demo.sh script should show how to start the daemon and the app, and then ticking an accomplishment in the demo-app will award it to you (with corresponding notify-osd bubble) and put the trophy file in examples/trophies/demo-app/*.trophy. Note that locked accomplishments (those for which the dependencies are not yet accomplished) are struck-through; you cannot “unaward” an accomplishment; the demo.sh script deletes all awarded trophies every time it’s run.

You can test the scriptrunner by running demo.sh in one terminal and then, while the demo-app is still running, run the scriptrunner in another terminal. (The scriptrunner uses the daemon’s D-Bus API and hence requires the daemon to be running; on a live system this would happen by D-Bus activation.)

The daemon has a test suite; run python libaccomplishments-daemon/tests/tests.py for it.

Smile :)

AccomplishmentsSpec (last edited 2012-02-08 08:48:06 by jonobacon)