diff --git a/.ci/build.bash b/.ci/build.bash
new file mode 100644
index 0000000000000000000000000000000000000000..3b12342fa078c13cf9d0c912c120602fcecb6cc5
--- /dev/null
+++ b/.ci/build.bash
@@ -0,0 +1,40 @@
+#!/bin/bash
+set -e
+set -x
+
+# Debug printing
+whoami
+env | sort
+
+if [ -f .ci/env ]; then
+    # add quotes to all vars (but do it once)
+    sudo sed -i -E 's/="*(.*[^"])"*$/="\1"/' .ci/env 
+    source '.ci/env'
+fi
+
+if [ -z ${PYTHON_VERSION_MAJOR_MINOR} ]; then
+    export PYTHON_VERSION_MAJOR=$(python -c "import sys; print(sys.version_info.major)")
+    export PYTHON_VERSION_MAJOR_MINOR=$(python -c "import sys; print('{}.{}'.format(sys.version_info.major, sys.version_info.minor))")
+fi
+
+# Force the build to happen in the build workspace, not in the container
+# This should be done at the beginning, but there are some circular dependencies
+# between Gazebo build artifacts (existing in the container) and nrp aliases/variables
+
+export HBP=$WORKSPACE
+cd $WORKSPACE
+export PYTHONPATH=
+source ${USER_SCRIPTS_DIR}/nrp_variables
+
+cd ${WORKSPACE}/${VIRTUAL_COACH_DIR}
+
+
+# Configure build
+export VIRTUAL_ENV_PATH=$VIRTUAL_ENV
+export NRP_INSTALL_MODE=dev
+export PYTHONPATH=hbp_nrp_virtual_coach:${VIRTUAL_ENV_PATH}/lib/python${PYTHON_VERSION_MAJOR_MINOR}/site-packages:$PYTHONPATH
+
+# Build
+export IGNORE_LINT='platform_venv|config_files|examples/integration_test/test_experiment_folder'
+make devinstall
+make verify_base -i
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000000000000000000000000000000000000..2ebcec55c982d4f43fbebff032fda6fb0a36f591
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,122 @@
+#!groovy
+// Load shared library at master branch
+// the path to the repo with this library should be specified in Jenkins
+// https://tomd.xyz/jenkins-shared-library/
+// https://www.jenkins.io/doc/book/pipeline/shared-libraries/
+@Library('nrp-shared-libs@master') _
+
+pipeline {
+    environment {
+        USER_SCRIPTS_DIR = "user-scripts"
+        ADMIN_SCRIPTS_DIR = "admin-scripts"
+        GAZEBO_ROS_DIR = "GazeboRosPackages"
+        VIRTUAL_COACH_DIR = "VirtualCoach"
+        // GIT_CHECKOUT_DIR is a dir of the main project (that was pushed)
+        GIT_CHECKOUT_DIR = "${env.VIRTUAL_COACH_DIR}"
+
+        TOPIC_BRANCH = selectTopicBranch(env.BRANCH_NAME, env.CHANGE_BRANCH)
+        DEFAULT_BRANCH = 'development'
+
+        NRP_COVERAGE_LINE=50
+        NRP_COVERAGE_BRANCH=0
+    }
+    agent {
+        docker {
+            // NEXUS_REGISTRY_IP and NEXUS_REGISTRY_PORT are Jenkins global variables
+            image "${env.NEXUS_REGISTRY_IP}:${env.NEXUS_REGISTRY_PORT}/nrp:development"
+            args '--entrypoint="" -u root --privileged'
+        }
+    }
+    options { 
+        // Skip code checkout prior running pipeline (only Jenkinsfile is checked out)
+        skipDefaultCheckout true
+    }
+
+    stages {
+        stage('Code checkout') {
+            steps {
+                // clear workspace
+                sh "rm -rf *"
+                // Notify BitBucket on the start of the job
+                // The Bitbucket Build Status Notifier is used
+                // REF: https://plugins.jenkins.io/bitbucket-build-status-notifier/
+                
+                bitbucketStatusNotify(buildState: 'INPROGRESS', buildName: 'Code checkout')
+
+                // Debug information on available environment
+                echo sh(script: 'env|sort', returnStdout: true)
+
+                // Checkout main project to GIT_CHECKOUT_DIR
+                dir(env.GIT_CHECKOUT_DIR) {
+                    checkout scm
+                    sh 'chown -R "${USER}" ./'
+                }
+
+                // Clone all dependencies
+                cloneRepoTopic(env.USER_SCRIPTS_DIR,  'git@bitbucket.org:hbpneurorobotics/user-scripts.git',      env.TOPIC_BRANCH, env.DEFAULT_BRANCH,     '${USER}')
+                cloneRepoTopic(env.GAZEBO_ROS_DIR,    'git@bitbucket.org:hbpneurorobotics/gazeborospackages.git', env.TOPIC_BRANCH, env.DEFAULT_BRANCH,  '${USER}')
+                cloneRepoTopic(env.ADMIN_SCRIPTS_DIR, 'git@bitbucket.org:hbpneurorobotics/admin-scripts.git',     env.TOPIC_BRANCH, 'master',       '${USER}')
+
+            }
+        }
+
+        stage('Build GazeboRosPackages') {
+            steps {
+                bitbucketStatusNotify(buildState: 'INPROGRESS', buildName: 'Building GazeboRosPackages')
+                
+                // Use GazeboRosPackages build script
+                dir(env.GAZEBO_ROS_DIR){
+                    // Determine explicitly the shell as bash (needed for proper user-scripts operation)
+                    sh 'bash .ci/build.bash ${WORKSPACE}/${USER_SCRIPTS_DIR}/'
+                }
+                
+            }
+        }
+
+        stage('Build VirtualCoach') {
+            steps {
+                bitbucketStatusNotify(buildState: 'INPROGRESS', buildName: 'Building VirtualCoach')
+
+                // Determine explicitly the shell as bash (needed for proper user-scripts operation)
+                dir(env.GIT_CHECKOUT_DIR){
+                    // this is a workaround to pass all env vars into script run by the other user (now we are root)
+                    sh 'env > .ci/env'
+                    sh 'sudo -H -u bbpnrsoa bash .ci/build.bash'
+
+                    // deliver artifacts
+                    step([$class: 'CoberturaPublisher', 
+                        autoUpdateHealth: true, 
+                        autoUpdateStability: false, 
+                        coberturaReportFile: 'coverage.xml', 
+                        failUnhealthy: true, 
+                        failUnstable: false, 
+                        maxNumberOfBuilds: 0, 
+                        onlyStable: false, 
+                        sourceEncoding: 'ASCII', 
+                        zoomCoverageChart: false,
+                        lineCoverageTargets: "90.0, 0, 0"])
+                    archiveArtifacts 'coverage.xml'
+                }
+            }
+        }
+    }
+
+    post {
+        always {
+            dir(env.GIT_CHECKOUT_DIR){
+                archiveArtifacts 'p*.*'
+                archiveArtifacts 'test-reports/*.*'
+                junit 'test-reports/*.xml'
+            }
+        }
+        aborted {
+            bitbucketStatusNotify(buildState: 'FAILED', buildDescription: 'Build aborted!')
+        }
+        failure {
+            bitbucketStatusNotify(buildState: 'FAILED', buildDescription: 'Build failed, see console output!')
+        }
+        success{
+            bitbucketStatusNotify(buildState: 'SUCCESSFUL', buildDescription: 'branch ' + env.GIT_BRANCH)
+        }
+    }
+}
diff --git a/hbp_nrp_virtual_coach/pynrp/__init__.py b/hbp_nrp_virtual_coach/pynrp/__init__.py
index 2cb21853049f66bfb4a828a6ea6b2d32d9adc9b2..45c1e21cd1a9afcb7442b0f84a7619b13755e786 100644
--- a/hbp_nrp_virtual_coach/pynrp/__init__.py
+++ b/hbp_nrp_virtual_coach/pynrp/__init__.py
@@ -3,4 +3,4 @@ This package contains the Virtual Coach implementation and interfaces to the Neu
 Platform backend services.
 """
 
-from pynrp.version import VERSION as __version__  # pylint: disable=W0611
\ No newline at end of file
+from pynrp.version import VERSION as __version__  # pylint: disable=W0611
diff --git a/hbp_nrp_virtual_coach/pynrp/simulation.py b/hbp_nrp_virtual_coach/pynrp/simulation.py
index d920dc028a6da6482020a2372266ba259b4d7fae..dc30bcc657ac3ed86d7f386b80bcb24fcc80da77 100644
--- a/hbp_nrp_virtual_coach/pynrp/simulation.py
+++ b/hbp_nrp_virtual_coach/pynrp/simulation.py
@@ -90,7 +90,7 @@ class Simulation(object):
         # when we have more information for this particular simulation
         self.__logger = logging.getLogger('Simulation')
 
-    # pylint: disable=too-many-locals
+    # pylint: disable=too-many-locals, too-many-arguments
     def launch(self, experiment_id, experiment_conf, server, reservation, cloned=True,
                storage_token=None, brain_processes=1, profiler='disabled'):
         """
diff --git a/hbp_nrp_virtual_coach/pynrp/virtual_coach.py b/hbp_nrp_virtual_coach/pynrp/virtual_coach.py
index 07c28c35a64b04fa4f548e74c3ab73f2751dffe9..553756b0f2a4e4d58dbeb5b40b81197adc019add 100644
--- a/hbp_nrp_virtual_coach/pynrp/virtual_coach.py
+++ b/hbp_nrp_virtual_coach/pynrp/virtual_coach.py
@@ -249,7 +249,8 @@ class VirtualCoach(object):
 
         return token
 
-    def launch_experiment(self, experiment_id, server=None, reservation=None, cloned=True, brain_processes=1,
+    def launch_experiment(self, experiment_id,
+                          server=None, reservation=None, cloned=True, brain_processes=1,
                           profiler='disabled'):
         """
         Attempts to launch a simulation with the given parameters. If no server is explicitly given
@@ -265,7 +266,8 @@ class VirtualCoach(object):
         :param cloned: (optional) True or False depending on if the launched
                        is a cloned experiment or not.
         :param brain_processes: (optional) Number of mpi processes in the brain simulation.
-        :param profiler: (optional) profiler option. Possible values are: disabled, cle_step and cprofile.
+        :param profiler: (optional) profiler option.
+                         Possible values are: disabled, cle_step and cprofile.
         """
         assert isinstance(experiment_id, string_types)
         assert isinstance(server, (string_types, type(None)))