Getting Started with Plugin Development


The following are the absolutely minimal set of software required to build and run Ajenti:

  • git
  • coffee-script (use NPM)
  • lessc (use NPM)

If you don’t have CoffeeScript or LESS compiler, you won’t be able to make changes to Ajenti CSS/JS files. In this case, download sources from PyPI, which includes compiled CSS/JS resources.

Debian/Ubuntu extras:

  • apt-show-versions
  • python-dbus (ubuntu)

Setting up

Download the source:

git clone git://

(or download them from PyPI:

Install the dependencies:

[sudo] pip install -Ur requirements.txt

Launch Ajenti in debug mode:

make run

Navigate to http://localhost:8000/.

Press Ctrl-at any time to launch an interactive Python shell and Ctrl-D to resume Ajenti.

CoffeeScript and LESS files will be recompiled automatically when you refresh the page; Python code will not. Additional debug information will be available in the console output and browser console.

Ajenti source code includes various example plugins under Demo category; their source is available in ajenti/plugins/test directory.

Creating new plugin package

New plugins can be placed in both <source>/ajenti/plugins/ (if you expect inclusion in the source tree) and /var/lib/ajenti/plugins.

Each plugin package consists of few Python modules, which contain ajenti.api.plugin classes (plugins). Packages also may contain static files, CoffeeScript and LESS code, and XML user interface layouts:

* ajenti
  * plugins
    * test
      * content
        * css
          - 1.less
        * js
        * static
          - 3.png
      * layout
        - 4.xml


To get started, create an empty directory <source>/ajenti/plugins/test.

Place a file called there:

from ajenti.api import *
from ajenti.plugins import *

info = PluginInfo(

def init():
    import main

In the same directory, create module The comments explain the concept behind plugins architecture:

from ajenti.api import *

class IShape (object):
    This is an interface, specifying the methods required.
    def number_of_corners(self):

class Square (BasePlugin, IShape):
    A sample implementation, note the inheritance from both BasePlugin (optional but gives extra options such as context management) and the interface.

    def init(self):
        init() methods are automatically called for plugins, maintaining inheritance hierarchy
        print 'Square #%s initialized' % id(self)

    def number_of_corners(self):
        return 4

class Circle (BasePlugin, IShape):
    def number_of_corners(self):
        return 0

print 'IShape is implemented by', IShape.get_class()
foo = IShape.get()  # get/create any instance of any IShape implementation
# or, more verbose, IShape.get_class().new()
print 'foo corners:', foo.number_of_corners()

# The instances are by default singleton:
print foo == IShape.get()  # True

# But you can create separate ones:
foo2 = IShape.get_class().new()
print foo == foo2  # False, different instances

for another_foo in IShape.get_all():  # iterate over all possible IShape implementations
    print '\n%s says:' % another_foo, another_foo.number_of_corners()

print IShape.get_instances()  # lists all three active IShape instances


IShape is implemented by <class 'ajenti.plugins.test.main.Square'>
Square #24838864 initialized
foo corners: 4
Square #24838928 initialized

<ajenti.plugins.test.main.Square object at 0x17b02d0> says: 4
<ajenti.plugins.test.main.Circle object at 0x17b0390> says: 0
[<ajenti.plugins.test.main.Square object at 0x17b02d0>, <ajenti.plugins.test.main.Square object at 0x17b0310>, <ajenti.plugins.test.main.Circle object at 0x17b0390>]

Learn about more interface and plugin methods here: ajenti.api.plugin

Continue to User Interface

comments powered by Disqus