diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2cf4c283a4cbfd59833a4d76837da48948dbe9f1..4327ea12f5523885cc462554bce4c7efcb93eab0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -330,6 +330,7 @@ endif()
 add_subdirectory(modules)
 add_subdirectory(scripts)
 add_subdirectory(tools)
+add_subdirectory(actions)
 # deployment has to come last, to ensure that all install commands are run before deployment
 # magic is done
 add_subdirectory(deployment)
diff --git a/actions/CMakeLists.txt b/actions/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bda606e42db6c6a8f839389381e879aae495fed8
--- /dev/null
+++ b/actions/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_custom_target(actions ALL)
+
+ost_action_init()
+# ost_action(awesome-action actions)
diff --git a/cmake_support/OST.cmake b/cmake_support/OST.cmake
index 8e4e243432396a870b007da628e04713ac021c6f..4364b0c9407b4f82c3cd1cbb41f69cb09c217a73 100644
--- a/cmake_support/OST.cmake
+++ b/cmake_support/OST.cmake
@@ -929,3 +929,49 @@ macro(setup_boost)
   set(BOOST_THREAD ${Boost_LIBRARIES})
   set(Boost_LIBRARIES)
 endmacro()
+
+
+#-------------------------------------------------------------------------------
+# Synopsis:
+#   ost_action_init()
+#
+# Description:
+#   Initialise cached variables
+#-------------------------------------------------------------------------------
+macro(ost_action_init)
+  set(OST_ACTION_NAMES "" CACHE INTERNAL "" FORCE)
+endmacro(ost_action_init)
+
+#-------------------------------------------------------------------------------
+# Synopsis:
+#   ost_action(ACTION TARGET)
+#
+# Description:
+#   Add a script to actions.
+#   ACTION script to be added (needs to have permissions to be executed)
+#   TARGET make target to add the action to
+#-------------------------------------------------------------------------------
+macro(ost_action ACTION TARGET)
+  copy_if_different("${CMAKE_CURRENT_SOURCE_DIR}"
+                    "${STAGE_DIR}/${LIBEXEC_PATH}" 
+                    "${ACTION}" "TARGETS" ${TARGET})
+  install(FILES "${ACTION}" DESTINATION "${LIBEXEC_PATH}"
+          PERMISSIONS WORLD_EXECUTE GROUP_EXECUTE OWNER_EXECUTE 
+                      WORLD_READ GROUP_READ OWNER_READ)
+  # storing tool names for bash completion
+  string(REGEX REPLACE "^ost-" "" stripped_action ${ACTION})
+  if(DEFINED OST_ACTION_NAMES)
+    if(${OST_ACTION_NAMES} MATCHES "${stripped_action}")
+      set(_ACTION_NAMES "${OST_ACTION_NAMES}")
+    else()
+      if("${OST_ACTION_NAMES}" STREQUAL "")
+        set(_ACTION_NAMES "${stripped_action}")
+      else()
+        set(_ACTION_NAMES "${OST_ACTION_NAMES} ${stripped_action}")
+      endif()
+    endif()
+  else()
+    set(_ACTION_NAMES "${stripped_action}")
+  endif()
+  set(OST_ACTION_NAMES "${_ACTION_NAMES}" CACHE INTERNAL "" FORCE)
+endmacro(ost_action)
\ No newline at end of file
diff --git a/modules/doc/contributing.rst b/modules/doc/contributing.rst
index c87c2daa0dc39444490415d69b489f9c1d5dbdcb..c171b7c0ddf1304876a2a78e60d063ff6fc63cb2 100644
--- a/modules/doc/contributing.rst
+++ b/modules/doc/contributing.rst
@@ -109,3 +109,74 @@ If you got a patch from someone else and would like to use apply it to your repo
 .. code-block:: bash
 
   git am < changeset.diff
+
+Starting Your Own Action
+--------------------------------------------------------------------------------
+In OST we call scripts/ programs 'actions'. They are started by a
+launcher found in your staging directory at :file:`stage/bin/ost`. This little
+guy helps keeping the shell environment in the right mood to carry out your
+job. So usually you will start an action by
+
+.. code-block:: console
+
+   $ stage/bin/ost --help
+
+Starting new action **do** go for a dedicated branch for action-development.
+There you can produce intermediate commits while other branches stay clean in
+case you have to do some work there which needs to get public.
+
+After preparing your repository its time to create a file for the action. That
+is a bit different than for modules. Assuming we are sitting in the
+repository's root:
+
+.. code-block:: console
+
+   $ touch action/ost-awesome-action
+   $ chmod +x action/ost-awesome-action
+
+Two things are important here: actions are prefixed with :file:`ost-`, so they
+are recognised by the :file:`ost` launcher. Secondly, action files need to be
+executable, which does not propagate if you do it **after** the first call to
+``make``.
+
+To get the new action recognised by ``make`` to be placed in
+:file:`stage/libexec/openstructure`, it has to be registered with ``cmake`` in
+:file:`actions/CMakeLists.txt`:
+
+.. code-block:: console
+  :linenos:
+
+   add_custom_target(actions ALL)
+
+   ost_action_init()
+   ost_action(ost-awesome-action actions)
+
+Just add your action with its full filename with a call to `ost_action` at
+the end of the file.
+
+Now its time to fill your action with code. Instead of reading a lot more of
+explanations, it should be easy to go by examples from the :file:`actions`
+directory. There are only two really important points:
+
+* No shebang line (``#! /usr/bin/python``) in your action! Also no
+  ``#! /usr/bin/env python`` or anything like this. This may lead to funny side
+  effects, like calling a ``python`` interpreter from outside a virtual
+  environment or calling a different version. Basically it may mess up the
+  environment your action is running in. Actions are called by :file:`ost`,
+  that's enough to get everything just right.
+
+* The action of your action happens in the ost branch of the script.
+  Your action will have own function definitions, variables and all the bells
+  and whistles. Hiding behind ost keeps everything separated and makes
+  things easier when it gets to debugging. So just after
+
+  .. code-block:: python
+
+     import alot
+
+     def functions_specific_to_your_action(...):
+
+     if __name__ == "__main__":
+         <put together what your action should do here>
+
+  start putting your action together.
diff --git a/scripts/ost.in b/scripts/ost.in
index f610b2446b4cddb8591d528cf2633879db0bd656..aca9ea26e5d4aa46d50489cc6d70b257f8c78aee 100755
--- a/scripts/ost.in
+++ b/scripts/ost.in
@@ -28,9 +28,35 @@ else
   SCRIPT_NAME="$0"
 fi
 BIN_DIR=`dirname "$SCRIPT_NAME"`
+OST_EXEC_DIR=$(cd $BIN_DIR/../@LIBEXEC_PATH@ && pwd)
+export OST_EXEC_DIR
 
-source "$BIN_DIR/../@LIBEXEC_PATH@/ost_config"
+source "$OST_EXEC_DIR/ost_config"
 
-$pyexec $interactive -c "execfile('$DNG_ROOT/@LIBDIR@/python@PYTHON_VERSION@/site-packages/ost/ost_startup.py')" $opts
-RC=$?
-exit $RC
+ACTION="$1"
+OST_SCRIPT="${OST_EXEC_DIR}/ost-${ACTION}"
+
+IFS="#"
+if test -e "${OST_SCRIPT}" ; then
+    opts=""
+    for argument in "${@:2}";do
+      if [ -n "$opts" ]; then
+        opts=$opts"#""$argument"
+      else
+        opts="$argument"
+      fi
+    done
+    $pyexec -c "execfile('$DNG_ROOT/@LIBDIR@/python@PYTHON_VERSION@/site-packages/ost/ost_startup.py')" "${OST_SCRIPT}" $opts
+else
+    opts=""
+    for argument in "$@";do
+      if [ -n "$opts" ]; then
+        opts=$opts"#""$argument"
+      else
+        opts="$argument"
+      fi
+    done
+    $pyexec $interactive -c "execfile('$DNG_ROOT/@LIBDIR@/python@PYTHON_VERSION@/site-packages/ost/ost_startup.py')" $opts
+    RC=$?
+    exit $RC
+fi
diff --git a/scripts/ost_config.in b/scripts/ost_config.in
index afce131f195b2f17c0198ac7439402916b15f4fb..cda517095e9a64426b97e670bb3f130c44113860 100644
--- a/scripts/ost_config.in
+++ b/scripts/ost_config.in
@@ -76,15 +76,6 @@ fi
 
 set -o noglob
 
-opts=""
-for argument in "$@";do
-  if [ -n "$opts" ]; then
-    opts=$opts"#""$argument"
-  else
-    opts="$argument"
-  fi
-done
-
 # decide whether to start interactively or not
 # interactive mode can be forced by setting -i as a iplt option
 interactive=""
@@ -95,6 +86,3 @@ else
     interactive="-i"
   fi
 fi
-
-
-IFS="#"
diff --git a/scripts/ost_startup.py.in b/scripts/ost_startup.py.in
index 612b6485cf2515deffe6023f80e3ea4ea14e8ce5..d3cac43d8daa106a882f696bf8ee02db7ccb5c39 100644
--- a/scripts/ost_startup.py.in
+++ b/scripts/ost_startup.py.in
@@ -1,4 +1,4 @@
-import sys, os, platform
+import sys, os, platform, glob
 import optparse
 
 def show_help(option, opt, value, parser):
@@ -11,7 +11,22 @@ def interactive_flag(option, opt, value, parser):
 def stop():
   sys.exit(0)
 
-usage = 'usage: ost [ost options] [script to execute] [script parameters]'
+usage = """
+
+    ost [ost options] [script to execute] [script parameters]
+
+or
+    ost [action name] [action options]
+
+"""
+
+action_path = os.path.abspath(os.environ.get("OST_EXEC_DIR", ""))
+
+usage += 'Following actions are available:\n'
+for action in sorted(glob.glob(os.path.join(action_path, 'ost-*'))):
+    usage += "  %s\n" % action[len(action_path)+5:]
+usage += '\nEach action should respond to "--help".\n'
+
 class OstOptionParser(optparse.OptionParser):
   def __init__(self, **kwargs):
     optparse.OptionParser.__init__(self, **kwargs)