diff --git a/slapos/recipe/apacheperl/__init__.py b/slapos/recipe/apacheperl/__init__.py
index fe5d06dd54966bcb3cc428d7412dbebe115cfabd..36b38bc5bb1655e0a64bca702f3b8078a844b1c8 100644
--- a/slapos/recipe/apacheperl/__init__.py
+++ b/slapos/recipe/apacheperl/__init__.py
@@ -57,10 +57,9 @@ class Recipe(GenericBaseRecipe):
     )
     path_list.append(httpd_conf)
 
-    wrapper = self.createPythonScript(self.options['wrapper'],
-        'slapos.recipe.librecipe.execute.generic_exec',
-        ((self.options['httpd-binary'], '-f', self.options['httpd-conf'],
-          '-DFOREGROUND'),)
+    wrapper = self.createWrapper(self.options['wrapper'],
+        (self.options['httpd-binary'], '-f', self.options['httpd-conf'],
+          '-DFOREGROUND'),
     )
     path_list.append(wrapper)
 
diff --git a/slapos/recipe/apachephp/__init__.py b/slapos/recipe/apachephp/__init__.py
index 670dcd4f5d73e13807c9c7da29dba9495b3e034f..2a701f8657621bd9dcc83b9d5292943176a11421 100644
--- a/slapos/recipe/apachephp/__init__.py
+++ b/slapos/recipe/apachephp/__init__.py
@@ -92,14 +92,13 @@ class Recipe(GenericBaseRecipe):
       )
       path_list.append(httpd_conf)
 
-    wrapper = self.createWrapper(name=self.options['wrapper'],
-                                 command=self.options['httpd-binary'],
-                                 parameters=[
+    wrapper = self.createWrapper(self.options['wrapper'],
+                                 (self.options['httpd-binary'],
                                      '-f',
                                      self.options['httpd-conf'],
                                      '-DFOREGROUND'
-                                     ],
-                                 environment=self.environ)
+                                     ),
+                                 self.environ)
     path_list.append(wrapper)
 
     secret_key_filename = os.path.join(self.buildout['buildout']['directory'],
diff --git a/slapos/recipe/apacheproxy/__init__.py b/slapos/recipe/apacheproxy/__init__.py
index 0d6b3528679b9945bac7454319de2d61cc76d414..4c9a019ffcb444d7dae5d9f36c889731d156da8e 100644
--- a/slapos/recipe/apacheproxy/__init__.py
+++ b/slapos/recipe/apacheproxy/__init__.py
@@ -49,13 +49,12 @@ class Recipe(GenericBaseRecipe):
     )
     path_list.append(httpd_conf)
 
-    wrapper = self.createWrapper(name=self.options['wrapper'],
-                                 command=self.options['httpd-binary'],
-                                 parameters=[
+    wrapper = self.createWrapper(self.options['wrapper'],
+                                 (self.options['httpd-binary'],
                                      '-f',
                                      self.options['httpd-conf'],
                                      '-DFOREGROUND',
-                                     ])
+                                     ))
 
     path_list.append(wrapper)
 
diff --git a/slapos/recipe/boinc/__init__.py b/slapos/recipe/boinc/__init__.py
index 0cedf1594e471932dd7fac2d559def44ffa62ee0..7f79accf1e26565806382bcee3dc5419ead84561 100644
--- a/slapos/recipe/boinc/__init__.py
+++ b/slapos/recipe/boinc/__init__.py
@@ -124,9 +124,8 @@ class Recipe(GenericBaseRecipe):
 
     #Generate wrapper for php
     wrapperphp = os.path.join(self.home, 'bin/php')
-    php_wrapper = self.createPythonScript(wrapperphp,
-        'slapos.recipe.librecipe.execute.generic_exec',
-        ((self.phpbin, '-c', self.phpini),)
+    php_wrapper = self.createWrapper(wrapperphp,
+        (self.phpbin, '-c', self.phpini),
     )
     path_list.append(php_wrapper)
 
@@ -406,11 +405,10 @@ class Client(GenericBaseRecipe):
     path_list.append(cmd)
 
     #Generate BOINC client wrapper
-    boinc = self.createPythonScript(boinc_wrapper,
-            'slapos.recipe.librecipe.execute.generic_exec',
-            ((boincbin, '--allow_multiple_clients', '--gui_rpc_port',
+    boinc = self.createWrapper(boinc_wrapper,
+            (boincbin, '--allow_multiple_clients', '--gui_rpc_port',
               str(self.options['rpc-port']), '--allow_remote_gui_rpc',
-              '--dir', installdir, '--redirectio', '--check_all_logins'),)
+              '--dir', installdir, '--redirectio', '--check_all_logins'),
     )
     path_list.append(boinc)
 
diff --git a/slapos/recipe/bonjourgrid/__init__.py b/slapos/recipe/bonjourgrid/__init__.py
index 5fcb965fa981af394ad5dbe6005def0add312c8c..0664a332ebb815f52b2fc2d7f8ec20ef687587c1 100644
--- a/slapos/recipe/bonjourgrid/__init__.py
+++ b/slapos/recipe/bonjourgrid/__init__.py
@@ -73,16 +73,15 @@ class Recipe(GenericBaseRecipe):
     bg_wrapper = self.options['wrapper'].strip()
     log = self.options['log_file'].strip()
     pid_file = self.options['pid_file'].strip()
-    wrapper = self.createPythonScript(bg_wrapper,
-        'slapos.recipe.librecipe.execute.generic_exec',
-        ((python, bonjourgrid_master, '--log_file', log,
+    wrapper = self.createWrapper(bg_wrapper,
+        (python, bonjourgrid_master, '--log_file', log,
           '--pid_file', pid_file,
           '--master_wrapper', grid_wrapper,
           '--directory', self.options['work_dir'].strip(),
           '--server', self.options['redis-url'].strip(),
           '--port', self.options['redis-port'].strip(),
           '--num_workers', self.options['nworkers'].strip(),
-         ),)
+         ),
     )
     path_list.append(wrapper)
 
@@ -113,9 +112,8 @@ class Client(GenericBaseRecipe):
     bg_wrapper = self.options['wrapper'].strip()
     log = self.options['log_file'].strip()
     pid_file = self.options['pid_file'].strip()
-    wrapper = self.createPythonScript(bg_wrapper,
-        'slapos.recipe.librecipe.execute.generic_exec',
-        ((python, bonjourgrid_client, '--log_file', log,
+    wrapper = self.createWrapper(bg_wrapper,
+        (python, bonjourgrid_client, '--log_file', log,
           '--pid_file', pid_file,
           '--boinc_wrapper', boinc_script,
           '--condor_wrapper', condor_script,
@@ -123,7 +121,7 @@ class Client(GenericBaseRecipe):
           '--install_directory', self.options['install_dir'].strip(),
           '--server', self.options['redis-url'].strip(),
           '--port', self.options['redis-port'].strip(),
-         ),)
+         ),
     )
     path_list.append(wrapper)
 
diff --git a/slapos/recipe/certificate_authority/__init__.py b/slapos/recipe/certificate_authority/__init__.py
index 76ee32957ac56ffd2998080f425cbd5b4478065d..14a66cf9209876c78990cc81c7fbd65496f41721 100644
--- a/slapos/recipe/certificate_authority/__init__.py
+++ b/slapos/recipe/certificate_authority/__init__.py
@@ -137,11 +137,10 @@ class Request(Recipe):
 
     path_list = [key_file, cert_file]
     if request_needed:
-      wrapper = self.createPythonScript(
+      wrapper = self.createWrapper(
         self.options['wrapper'],
-        'slapos.recipe.librecipe.execute.generic_exec',
-        ((self.options['executable'],),),
-        {'wait_list': (certificate, key)},
+        (self.options['executable'],),
+        wait_list=(certificate, key),
       )
       path_list.append(wrapper)
 
diff --git a/slapos/recipe/cloud9/__init__.py b/slapos/recipe/cloud9/__init__.py
index 09a0bc7c696fb226ce89eebec2c14ee1e7c23669..2135aec95e3aca96a64f8616b1876d69e8641bf5 100644
--- a/slapos/recipe/cloud9/__init__.py
+++ b/slapos/recipe/cloud9/__init__.py
@@ -49,7 +49,4 @@ class Recipe(GenericBaseRecipe):
     cloud9_args = [self.node_executable, self.cloud9, '-l', self.ip, '-p',
         self.port, '-w', self.workdir]
 
-    return self.createPythonScript(self.wrapper,
-        'slapos.recipe.librecipe.execute.generic_exec',
-        (cloud9_args, environment)
-    )
+    return self.createWrapper(self.wrapper, cloud9_args, environment)
diff --git a/slapos/recipe/davstorage/__init__.py b/slapos/recipe/davstorage/__init__.py
index 1b956909f0d8d5a537c3d73972d1dd911683eb99..64b0e41e294a8ded6c7d3704639f60476402a5a6 100644
--- a/slapos/recipe/davstorage/__init__.py
+++ b/slapos/recipe/davstorage/__init__.py
@@ -98,9 +98,8 @@ class Recipe(GenericBaseRecipe):
     )
     path_list.append(config_file)
 
-    wrapper = self.createPythonScript(self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['apache-binary'], '-f', config_file, '-DFOREGROUND'),))
+    wrapper = self.createWrapper(self.options['wrapper'],
+      (self.options['apache-binary'], '-f', config_file, '-DFOREGROUND'))
     path_list.append(wrapper)
 
     promise = self.createPythonScript(self.options['promise'],
diff --git a/slapos/recipe/dcron.py b/slapos/recipe/dcron.py
index e274cc48692fd4a32064de4711b8ad36fe7d6aa7..0478448f30b0c85f9c1b2ff2f54fbd7ad6eea35a 100644
--- a/slapos/recipe/dcron.py
+++ b/slapos/recipe/dcron.py
@@ -35,15 +35,14 @@ class Recipe(GenericBaseRecipe):
     self.logger.info("Installing dcron...")
 
     options = self.options
-    script = self.createWrapper(name=options['binary'],
-                                command=options['dcrond-binary'].strip(),
-                                parameters=[
+    script = self.createWrapper(options['binary'],
+                                (options['dcrond-binary'].strip(),
                                     '-s', options['cron-entries'],
                                     '-c', options['crontabs'],
                                     '-t', options['cronstamps'],
                                     '-f', '-l', '5',
                                     '-M', options['catcher']
-                                    ])
+                                    ))
 
     self.logger.debug('Main cron executable created at : %r', script)
 
diff --git a/slapos/recipe/dropbear.py b/slapos/recipe/dropbear.py
index be53710cc2cc7eb37721cfc619730394222a5d6d..53a7db3d0f5d21eaf1e6a5c74942cbfd29989df9 100644
--- a/slapos/recipe/dropbear.py
+++ b/slapos/recipe/dropbear.py
@@ -93,11 +93,7 @@ class Recipe(GenericBaseRecipe):
     if 'shell' in self.options:
       env['DROPBEAR_OVERRIDE_SHELL'] = self.options['shell']
 
-    return self.createPythonScript(
-      self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      (dropbear_cmd, env)
-    )
+    return self.createWrapper(self.options['wrapper'], dropbear_cmd, env)
 
 class Client(GenericBaseRecipe):
 
@@ -115,11 +111,7 @@ class Client(GenericBaseRecipe):
     if 'identity-file' in self.options:
       dropbear_cmd.extend(['-i', self.options['identity-file']])
 
-    return self.createPythonScript(
-      self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      (dropbear_cmd, env)
-    )
+    return self.createWrapper(self.options['wrapper'], dropbear_cmd, env)
 
 
 class AddAuthorizedKey(GenericBaseRecipe):
diff --git a/slapos/recipe/duplicity.py b/slapos/recipe/duplicity.py
index fc3eaceac8ddbbfb39c69fe5a0ef505abddaf634..1fc97c5caffbbfa0fdfeb0d4c64150f876b703d1 100644
--- a/slapos/recipe/duplicity.py
+++ b/slapos/recipe/duplicity.py
@@ -46,5 +46,4 @@ class Recipe(GenericBaseRecipe):
       cmd.extend(options)
       cmd.extend([backup_directory, remote_url])
 
-    return self.createPythonScript(self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec', (cmd,))
+    return self.createWrapper(self.options['wrapper'], cmd)
diff --git a/slapos/recipe/equeue.py b/slapos/recipe/equeue.py
index fb3f1fe11ce00cde51564fcfefdb26d30d3af8f1..8a7221bf132a3f7bc9d702c4234546b710def4b0 100644
--- a/slapos/recipe/equeue.py
+++ b/slapos/recipe/equeue.py
@@ -30,23 +30,20 @@ class Recipe(GenericBaseRecipe):
 
   def install(self):
 
-    parameters = [
+    args = [
+      self.options['equeue-binary'],
       '--database', self.options['database'],
       '--logfile', self.options['log'],
       '--lockfile', self.options['lockfile']
     ]
 
     if 'takeover-triggered-file-path' in self.options:
-      parameters.extend(['--takeover-triggered-file-path', self.options['takeover-triggered-file-path']])
+      args += ('--takeover-triggered-file-path',
+               self.options['takeover-triggered-file-path'])
 
     if 'loglevel' in self.options:
-      parameters.extend(['--loglevel', self.options['loglevel']])
+      args += '--loglevel', self.options['loglevel']
 
-    parameters.append(self.options['socket'])
-
-    wrapper = self.createWrapper(name=self.options['wrapper'],
-                                 command=self.options['equeue-binary'],
-                                 parameters=parameters)
-
-    return [wrapper]
+    args.append(self.options['socket'])
 
+    return self.createWrapper(self.options['wrapper'], args)
diff --git a/slapos/recipe/erp5testnode/__init__.py b/slapos/recipe/erp5testnode/__init__.py
index c70a2f219a29330c2cb8a7ffb832e4281e6a7dec..c556a2b280a9ac27ad2c716ae1687c3eee2c8a71 100644
--- a/slapos/recipe/erp5testnode/__init__.py
+++ b/slapos/recipe/erp5testnode/__init__.py
@@ -68,17 +68,14 @@ class Recipe(GenericBaseRecipe):
     )
     self.path_list.append(configuration_file)
     self.path_list.append(
-      self.createPythonScript(
-        self.options['wrapper'],
-        'slapos.recipe.librecipe.execute.generic_exec',
-        ( # Command
+      self.createWrapper(self.options['wrapper'],
+          # Command
           ( self.options['testnode'], '-l', self.options['log-file'],
             configuration_file),
           # Environment
           {
             'GIT_SSL_NO_VERIFY': '1',
           }
-        ),
       )
     )
     self.installApache()
@@ -106,9 +103,8 @@ class Recipe(GenericBaseRecipe):
                                apache_config)
     )
     self.path_list.append(config_file)
-    wrapper = self.createPythonScript(self.options['httpd-wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['apache-binary'], '-f', config_file, '-DFOREGROUND'),))
+    wrapper = self.createWrapper(self.options['httpd-wrapper'],
+      (self.options['apache-binary'], '-f', config_file, '-DFOREGROUND'))
     self.path_list.append(wrapper)
     # create empty html page to not allow listing of /
     page = open(os.path.join(self.options['log-directory'], "index.html"), "w")
diff --git a/slapos/recipe/generic_mysql/__init__.py b/slapos/recipe/generic_mysql/__init__.py
index 30e1772d27aea588a516f51886f3509de619dc6f..16cd9f676a9bf4d2392f1a27bdbb081f497d1f70 100644
--- a/slapos/recipe/generic_mysql/__init__.py
+++ b/slapos/recipe/generic_mysql/__init__.py
@@ -165,15 +165,13 @@ class Recipe(GenericBaseRecipe):
           '--defaults-file=%s' % mysql_conf_file,
           '--socket=%s' % socket.strip(), '--user=root',
           '--ibbackup=%s'% self.options['xtrabackup-binary']]
-      innobackupex_incremental = self.createPythonScript(
+      innobackupex_incremental = self.createWrapper(
         self.options['innobackupex-incremental'],
-        'slapos.recipe.librecipe.execute.generic_exec',
-        (innobackupex_argument_list + ['--incremental'], environment))
+        innobackupex_argument_list + ['--incremental'], environment)
       path_list.append(innobackupex_incremental)
-      innobackupex_full = self.createPythonScript(
+      innobackupex_full = self.createWrapper(
         self.options['innobackupex-full'],
-        'slapos.recipe.librecipe.execute.generic_exec',
-        (innobackupex_argument_list, environment))
+        innobackupex_argument_list, environment)
       path_list.append(innobackupex_full)
       backup_controller = self.createPythonScript(self.options['backup-script'], __name__ + '.innobackupex.controller', [innobackupex_incremental, innobackupex_full, full_backup, incremental_backup])
       path_list.append(backup_controller)
@@ -221,10 +219,9 @@ class Recipe(GenericBaseRecipe):
           '--defaults-file=%s' % mysql_conf_file,
           '--socket=%s' % socket.strip(), '--user=root',
           ]
-      pt_exe = self.createPythonScript(
+      pt_exe = self.createWrapper(
         os.path.join(self.options['bin-directory'], pt_script_name),
-        'slapos.recipe.librecipe.execute.generic_exec',
-        (pt_argument_list, environment))
+        pt_argument_list, environment)
       path_list.append(pt_exe)
 
     return path_list
diff --git a/slapos/recipe/haproxy/__init__.py b/slapos/recipe/haproxy/__init__.py
index b80673e75a70c2f8a30cf530983fd6465d174058..50b6d718cfec53cf65b87f33838f0b0bfeaeda52 100644
--- a/slapos/recipe/haproxy/__init__.py
+++ b/slapos/recipe/haproxy/__init__.py
@@ -120,10 +120,9 @@ class Recipe(GenericBaseRecipe):
          'server_text': server_snippet},
       )
     )
-    wrapper_path = self.createPythonScript(
+    wrapper_path = self.createWrapper(
       self.options['wrapper-path'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['binary-path'].strip(), '-f', configuration_path),))
+      (self.options['binary-path'].strip(), '-f', configuration_path))
     ctl_path = self.createPythonScript(
       self.options['ctl-path'],
       __name__ + '.haproxy.haproxyctl',
diff --git a/slapos/recipe/lampgeneric/__init__.py b/slapos/recipe/lampgeneric/__init__.py
index 662f70bf16128b64dc1f9827750fa6efb759aa73..695a72c4d2fdbc326ccd4cdf552cc2ae21d767d4 100644
--- a/slapos/recipe/lampgeneric/__init__.py
+++ b/slapos/recipe/lampgeneric/__init__.py
@@ -71,13 +71,12 @@ class Recipe(GenericBaseRecipe):
     )
     path_list.append(httpd_conf)
 
-    wrapper = self.createWrapper(name=self.options['wrapper'],
-                                 command=self.options['httpd-binary'],
-                                 parameters=[
+    wrapper = self.createWrapper(self.options['wrapper'],
+                                 (self.options['httpd-binary'],
                                      '-f',
                                      self.options['httpd-conf'],
                                      '-DFOREGROUND'
-                                     ])
+                                     ))
     path_list.append(wrapper)
 
 
diff --git a/slapos/recipe/librecipe/generic.py b/slapos/recipe/librecipe/generic.py
index 4556d782b0f71cf866d4c415bff4ba685aa1f185..cf2af11d8f91e65edf788a51f4f8b238c1a5762f 100644
--- a/slapos/recipe/librecipe/generic.py
+++ b/slapos/recipe/librecipe/generic.py
@@ -136,34 +136,39 @@ class GenericBaseRecipe(object):
       [(filename, module, function)], self._ws, sys.executable,
       path, arguments=', '.join(args))[0]
 
-  def createWrapper(self, name, command, parameters, environment=None):
-    """
-    Creates a basic shell script for process replacement.
-    Takes care of quoting.
-
-    This must be kept minimal to avoid code duplication with generic_exec.
-    In particular, do not implement workaround for shebang size limitation here
-    (note that this can't be done correctly with a POSIX shell, because the
-    process can't be given a name).
-    """
-    lines = [ '#!/bin/sh' ]
-
-    for key in environment or ():
-      lines.append('export %s=%s' % (key, shlex.quote(environment[key])))
-
-    lines.append('exec ' + shlex.quote(command))
-
-    parameters = map(shlex.quote, parameters)
-    parameters.append('"$@"')
-    for param in parameters:
+  def createWrapper(self, path, args, env=None, **kw):
+    """Create a wrapper script for process replacement"""
+    assert args
+    if kw:
+      return self.createPythonScript(path,
+        'slapos.recipe.librecipe.execute.generic_exec',
+        (args, env) if env else (args,), kw)
+
+    # Simple case: creates a basic shell script for process replacement.
+    # This must be kept minimal to avoid code duplication with generic_exec.
+    # In particular, do not implement workaround for shebang size limitation
+    # here (note that this can't be done correctly with a POSIX shell, because
+    # the process can't be given a name).
+
+    lines = ['#!/bin/sh']
+
+    if env:
+      for k, v in sorted(env.iteritems()):
+        lines.append('export %s=%s' % (k, shlex.quote(v)))
+
+    lines.append('exec')
+
+    args = map(shlex.quote, args)
+    args.append('"$@"')
+    for arg in args:
       if len(lines[-1]) < 40:
-        lines[-1] += ' ' + param
+        lines[-1] += ' ' + arg
       else:
         lines[-1] += ' \\'
-        lines.append('\t' + param)
+        lines.append('\t' + arg)
 
     lines.append('')
-    return self.createFile(name, '\n'.join(lines), 0700)
+    return self.createFile(path, '\n'.join(lines), 0700)
 
   def createDirectory(self, parent, name, mode=0700):
     path = os.path.join(parent, name)
diff --git a/slapos/recipe/logrotate.py b/slapos/recipe/logrotate.py
index c9f013d4f0d9a663d9b8b554a3a915398e8ca223..fdfc096550ee5e5c4060729aaec92be2fd6c9637 100644
--- a/slapos/recipe/logrotate.py
+++ b/slapos/recipe/logrotate.py
@@ -46,11 +46,10 @@ class Recipe(GenericBaseRecipe):
 
     state_file = self.options['state-file']
 
-    logrotate = self.createPythonScript(
+    logrotate = self.createWrapper(
       self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['logrotate-binary'],
-        '-s', state_file, logrotate_conf_file),)
+      (self.options['logrotate-binary'],
+        '-s', state_file, logrotate_conf_file),
     )
 
     return [logrotate, logrotate_conf_file]
diff --git a/slapos/recipe/mioga/instantiate.py b/slapos/recipe/mioga/instantiate.py
index a0978325ac44c6a2c99063975c04108e1a781ffa..13a4ec8ceef46bc5e77f26441d679373947079ac 100644
--- a/slapos/recipe/mioga/instantiate.py
+++ b/slapos/recipe/mioga/instantiate.py
@@ -203,11 +203,10 @@ Include conf/extra/httpd-autoindex.conf
 
     services_dir = self.options['services_dir']
 
-    httpd_wrapper = self.createPythonScript(
+    httpd_wrapper = self.createWrapper(
       os.path.join(services_dir, 'httpd_wrapper'),
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['httpd_binary'],
-        '-f', self.options['httpd_conf'], '-DFOREGROUND'),)
+      (self.options['httpd_binary'],
+        '-f', self.options['httpd_conf'], '-DFOREGROUND'),
     )
     path_list.append(httpd_wrapper)
 
@@ -220,19 +219,17 @@ Include conf/extra/httpd-autoindex.conf
 
     site_perl_bin = os.path.join(self.options['site_perl'], 'bin')
     mioga_conf_path = os.path.join(mioga_base, 'conf', 'Mioga.conf')
-    notifier_wrapper = self.createPythonScript(
+    notifier_wrapper = self.createWrapper(
       os.path.join(services_dir, 'notifier'),
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((os.path.join(site_perl_bin, 'notifier.pl'),
-        mioga_conf_path),)
+      (os.path.join(site_perl_bin, 'notifier.pl'),
+        mioga_conf_path),
     )
     path_list.append(notifier_wrapper)
 
-    searchengine_wrapper = self.createPythonScript(
+    searchengine_wrapper = self.createWrapper(
       os.path.join(services_dir, 'searchengine'),
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((os.path.join(site_perl_bin, 'searchengine.pl'),
-        mioga_conf_path),)
+      (os.path.join(site_perl_bin, 'searchengine.pl'),
+        mioga_conf_path),
     )
     path_list.append(searchengine_wrapper)
 
diff --git a/slapos/recipe/mysql/__init__.py b/slapos/recipe/mysql/__init__.py
index 6b962f32329807541f108de377bd38a166b0531a..a83cc50a2bea7cbdcc6b0fc7845bae7387dda364 100644
--- a/slapos/recipe/mysql/__init__.py
+++ b/slapos/recipe/mysql/__init__.py
@@ -53,11 +53,10 @@ class Recipe(GenericBaseRecipe):
 
     mysql_binary = self.options['mysql-binary']
     socket = self.options['socket'],
-    post_rotate = self.createPythonScript(
+    post_rotate = self.createWrapper(
       self.options['logrotate-post'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((mysql_binary, '--no-defaults', '-B', '-u', 'root',
-        '--socket=%s' % socket, '-e', 'FLUSH LOGS'),)
+      (mysql_binary, '--no-defaults', '-B', '-u', 'root',
+        '--socket=%s' % socket, '-e', 'FLUSH LOGS'),
     )
     path_list.append(post_rotate)
 
diff --git a/slapos/recipe/neoppod.py b/slapos/recipe/neoppod.py
index a277945e85b8556593a6385adc65ca9605b24f8d..4c0bcf5212e800276c6a54303da7b7871872f66b 100644
--- a/slapos/recipe/neoppod.py
+++ b/slapos/recipe/neoppod.py
@@ -42,7 +42,8 @@ class NeoBaseRecipe(GenericBaseRecipe):
       # Only then can this recipe start succeeding and actually doing anything
       # useful, as per NEO deploying constraints.
       raise UserError('"masters" parameter is mandatory')
-    option_list = [
+    args = [
+      options['binary'],
       # Keep the -l option first, as expected by logrotate snippets.
       '-l', options['logfile'],
       '-m', options['masters'],
@@ -53,17 +54,13 @@ class NeoBaseRecipe(GenericBaseRecipe):
     ]
     if options['ssl']:
       etc = os.path.join(self.buildout['buildout']['directory'], 'etc', '')
-      option_list += (
+      args += (
         '--ca', etc + 'ca.crt',
         '--cert', etc + 'neo.crt',
         '--key', etc + 'neo.key',
         )
-    option_list.extend(self._getOptionList())
-    return [self.createWrapper(
-      options['wrapper'],
-      options['binary'],
-      option_list
-    )]
+    args += self._getOptionList()
+    return self.createWrapper(options['wrapper'], args)
 
   def _getBindingAddress(self):
     options = self.options
diff --git a/slapos/recipe/notifier.py b/slapos/recipe/notifier.py
index a63374fa61c2b599426125d03bc148427599471b..281c4f0abb748b0365409e1cbf4d55ac6dadd2ef 100644
--- a/slapos/recipe/notifier.py
+++ b/slapos/recipe/notifier.py
@@ -33,16 +33,14 @@ class Recipe(GenericBaseRecipe):
   def install(self):
     options = self.options
     # Script that execute the callback(s) upon receiving a notification.
-    script = self.createWrapper(name=options['wrapper'],
-                                command=options['server-binary'],
-                                parameters=[
+    return self.createWrapper(options['wrapper'],
+                                (options['server-binary'],
                                    '--callbacks', options['callbacks'],
                                    '--feeds', options['feeds'],
                                    '--equeue-socket', options['equeue-socket'],
                                    options['host'], options['port']
-                                   ],
+                                   ),
                                 )
-    return [script]
 
 
 class Callback(GenericBaseRecipe):
@@ -98,16 +96,12 @@ class Notify(GenericBaseRecipe):
         '--status-item-directory', status_item_directory,
       )
 
+    kw = {}
     if pidfile:
-      return self.createPythonScript(wrapper,
-        'slapos.recipe.librecipe.execute.generic_exec',
-        (cmd,), {'pidfile': pidfile})
+      kw['pidfile'] = pidfile
 
     # Script that call an executable and send notification(s).
-    return self.createWrapper(name=wrapper,
-                              command=cmd[0],
-                              parameters=cmd[1:],
-                              )
+    return self.createWrapper(wrapper, cmd, **kw)
 
 
   def install(self):
diff --git a/slapos/recipe/novnc/__init__.py b/slapos/recipe/novnc/__init__.py
index 5e114bb4686866c428ef93441cb5a5db2bce1273..af06ddf861a9a93f5a830fa450e59c612e43acfe 100644
--- a/slapos/recipe/novnc/__init__.py
+++ b/slapos/recipe/novnc/__init__.py
@@ -35,10 +35,9 @@ class Recipe(GenericBaseRecipe):
   """
 
   def install(self):
-    return self.createPythonScript(
+    return self.createWrapper(
       self.options['path'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((
+      (
         self.options['websockify-path'],
         '--web',
         self.options['novnc-location'],
@@ -47,7 +46,7 @@ class Recipe(GenericBaseRecipe):
         '--ssl-only',
         '%s:%s' % (self.options['ip'], self.options['port']),
         '%s:%s' % (self.options['vnc-ip'], self.options['vnc-port']),
-       ),),
-      {'wait_list': (self.options['ssl-key-path'],
-                     self.options['ssl-cert-path'])},
+       ),
+      wait_list=(self.options['ssl-key-path'],
+                 self.options['ssl-cert-path']),
     )
diff --git a/slapos/recipe/pbs.py b/slapos/recipe/pbs.py
index 23c191600eb3edd110ae15cd9f5401714b764c0a..e1ee60cbe43fb9485fbd3405082dfb41c38b175b 100644
--- a/slapos/recipe/pbs.py
+++ b/slapos/recipe/pbs.py
@@ -320,12 +320,11 @@ class Recipe(GenericSlapRecipe, Notify, Callback):
     else:
       self.logger.info("Server mode")
 
-      wrapper = self.createWrapper(name=self.options['wrapper'],
-                                   command=self.options['rdiffbackup-binary'],
-                                   parameters=[
+      wrapper = self.createWrapper(self.options['wrapper'],
+                                   (self.options['rdiffbackup-binary'],
                                        '--restrict', self.options['path'],
                                        '--server'
-                                       ])
+                                       ))
       path_list.append(wrapper)
 
     return path_list
diff --git a/slapos/recipe/redis/__init__.py b/slapos/recipe/redis/__init__.py
index 428db90ddb387cd032d9f36ddde857fd180b04a4..49559455f959a898b8f1afe64980c2d24e2d6fbb 100644
--- a/slapos/recipe/redis/__init__.py
+++ b/slapos/recipe/redis/__init__.py
@@ -56,10 +56,9 @@ class Recipe(GenericBaseRecipe):
       configuration))
     path_list.append(config)
 
-    redis = self.createPythonScript(
+    redis = self.createWrapper(
       self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['server_bin'], config_file),)
+      (self.options['server_bin'], config_file),
     )
     path_list.append(redis)
 
diff --git a/slapos/recipe/reverse_proxy_nginx/__init__.py b/slapos/recipe/reverse_proxy_nginx/__init__.py
index 61a244bb985d16e1426969f611a7ab1fc5367398..785bca1aff07ad15425652248c99393c3b5091b0 100644
--- a/slapos/recipe/reverse_proxy_nginx/__init__.py
+++ b/slapos/recipe/reverse_proxy_nginx/__init__.py
@@ -70,14 +70,12 @@ class Recipe(GenericSlapRecipe):
     path_list.append(nginx_configuration_file)
     
     # Generate Nginx wrapper
-    wrapper = self.createWrapper(
-        name=self.options['wrapper'],
-        command=self.options['nginx-executable'],
-        parameters=[
+    path_list.append(self.createWrapper(
+        self.options['wrapper'],
+        (self.options['nginx-executable'],
             '-c', self.options['configuration-file'],
             '-p', self.options['home-directory']
-        ]
-    )
+        )))
 
     # TODO: reload configuration or have feature like apache_map
 
diff --git a/slapos/recipe/shell.py b/slapos/recipe/shell.py
index dda292729e66ae68f3d329839f929c0defec9363..f64d9685d606203b48a456e600b180815a71c7fc 100644
--- a/slapos/recipe/shell.py
+++ b/slapos/recipe/shell.py
@@ -32,14 +32,11 @@ class Recipe(GenericBaseRecipe):
 
   def install(self):
     ps1 = self.options.get('ps1')
+    shell = self.options['shell']
     env = {
       'HOME': self.options['home'],
       'PATH': ':'.join(self.options['path'].split('\n')),
       'PS1': str(json.loads(ps1)) if ps1 else os.getenv('PS1', '> '),
-      'SHELL': self.options['shell'],
+      'SHELL': shell,
     }
-    return self.createPythonScript(
-      self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['shell'],), env),
-    )
+    return self.createWrapper(self.options['wrapper'], (shell,), env)
diff --git a/slapos/recipe/sphinx/__init__.py b/slapos/recipe/sphinx/__init__.py
index de7bd46859f45b7f686a22eaabc01d1649dd25cb..bac224d84992530e531cb80adbd50ebb8600e647 100644
--- a/slapos/recipe/sphinx/__init__.py
+++ b/slapos/recipe/sphinx/__init__.py
@@ -48,11 +48,10 @@ class Recipe(GenericBaseRecipe):
     )
 
     # Create init script
-    wrapper = self.createPythonScript(
+    wrapper = self.createWrapper(
         self.options['wrapper'],
-        'slapos.recipe.librecipe.execute.generic_exec',
-        ((self.options['sphinx-searchd-binary'].strip(), '-c',
-          sphinx_conf_path, '--nodetach'),),
+        (self.options['sphinx-searchd-binary'].strip(), '-c',
+          sphinx_conf_path, '--nodetach'),
         )
 
     return [wrapper, sphinx_conf_path]
diff --git a/slapos/recipe/squid/__init__.py b/slapos/recipe/squid/__init__.py
index 17c31dae1a887523c75d665ef575aa8b64b8eb15..3f54b82616b717a92a78b117e82e456618f84d98 100644
--- a/slapos/recipe/squid/__init__.py
+++ b/slapos/recipe/squid/__init__.py
@@ -78,17 +78,15 @@ class Recipe(GenericBaseRecipe):
       self.substituteTemplate(template_filename, config))
 
     # Prepare directories
-    prepare_path = self.createPythonScript(
+    prepare_path = self.createWrapper(
       self.options['prepare-path'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['binary-path'].strip(),
-        '-z', '-f', configuration_path),))
+      (self.options['binary-path'].strip(),
+        '-z', '-f', configuration_path))
 
     # Create running wrapper
-    wrapper_path = self.createPythonScript(
+    wrapper_path = self.createWrapper(
       self.options['wrapper-path'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['binary-path'].strip(),
-        '-N', '-f', configuration_path),))
+      (self.options['binary-path'].strip(),
+        '-N', '-f', configuration_path))
 
     return [configuration_path, wrapper_path, prepare_path]
diff --git a/slapos/recipe/sshkeys_authority.py b/slapos/recipe/sshkeys_authority.py
index 82855ee266a733d2c3f9e4345a7644cace75b3c0..e8751ab43c34d68ab9a4086044d5b38274c279e3 100644
--- a/slapos/recipe/sshkeys_authority.py
+++ b/slapos/recipe/sshkeys_authority.py
@@ -152,10 +152,9 @@ class Request(GenericBaseRecipe):
     os.symlink(self.private_key, private_key_link)
     # end-XXX
 
-    wrapper = self.createPythonScript(
+    wrapper = self.createWrapper(
       self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['executable'],),),
-      {'wait_list': (self.private_key, self.public_key)})
+      (self.options['executable'],),
+      wait_list=(self.private_key, self.public_key))
 
     return [request_file, wrapper, public_key_link, private_key_link]
diff --git a/slapos/recipe/stunnel/__init__.py b/slapos/recipe/stunnel/__init__.py
index 124aefbdc49c080308ef7c09b8bbdbe70d8a9046..eb4b275269a4183a25ff0706abe3aa29eae722f9 100644
--- a/slapos/recipe/stunnel/__init__.py
+++ b/slapos/recipe/stunnel/__init__.py
@@ -79,10 +79,9 @@ class Recipe(GenericBaseRecipe):
       self.substituteTemplate(template, conf))
     path_list.append(conf_file)
 
-    wrapper = self.createPythonScript(
+    wrapper = self.createWrapper(
       self.options['wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['stunnel-binary'], conf_file),)
+      (self.options['stunnel-binary'], conf_file),
     )
     path_list.append(wrapper)
 
diff --git a/slapos/recipe/tidstorage/__init__.py b/slapos/recipe/tidstorage/__init__.py
index 5f2d15966eaad0f9566167b6008a251cbb9cb605..672abdf849ef540f21d41750ab19b7ee32fc0f93 100644
--- a/slapos/recipe/tidstorage/__init__.py
+++ b/slapos/recipe/tidstorage/__init__.py
@@ -36,19 +36,17 @@ class Recipe(GenericBaseRecipe):
     r = [configuration_file]
 
     wrapper = self.options.get('tidstorage-wrapper')
-    wrapper and r.append(self.createPythonScript(wrapper,
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['tidstoraged-binary'],
-        '--nofork', '--config', configuration_file),)))
+    wrapper and r.append(self.createWrapper(wrapper,
+      (self.options['tidstoraged-binary'],
+        '--nofork', '--config', configuration_file)))
 
-    r.append(self.createPythonScript(
+    r.append(self.createWrapper(
       self.options['repozo-wrapper'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['tidstorage-repozo-binary'],
+      (self.options['tidstorage-repozo-binary'],
         '--config', configuration_file,
         '--repozo', self.options['repozo-binary'],
         '--gzip',
         '--quick',
-       ),)))
+       )))
 
     return r
diff --git a/slapos/recipe/wrapper.py b/slapos/recipe/wrapper.py
index e47d0f376f08885b6829f22646087d3a254aea10..2f4dab0e2e67941b8c4801a3068f4abd6f92c166 100644
--- a/slapos/recipe/wrapper.py
+++ b/slapos/recipe/wrapper.py
@@ -40,7 +40,7 @@ class Recipe(GenericBaseRecipe):
     :param bool reserve-cpu: command will ask for an exclusive CPU core
     """
     def install(self):
-        command_line = shlex.split(self.options['command-line'])
+        args = shlex.split(self.options['command-line'])
         wrapper_path = self.options['wrapper-path']
         wait_files = self.options.get('wait-for-files')
         pidfile = self.options.get('pidfile')
@@ -60,17 +60,4 @@ class Recipe(GenericBaseRecipe):
         if self.isTrueValue(self.options.get('reserve-cpu')):
           kw['reserve_cpu'] = True
 
-        if kw:
-          # More complex needs: create a Python script as wrapper
-          args = [command_line]
-          if environment:
-            args.append(environment)
-
-          return self.createPythonScript(wrapper_path,
-            'slapos.recipe.librecipe.execute.generic_exec',
-            args, kw)
-
-        return self.createWrapper(wrapper_path,
-          command_line[0],
-          command_line[1:],
-          environment=environment)
+        return self.createWrapper(wrapper_path, args, environment, **kw)
diff --git a/slapos/recipe/zeo/__init__.py b/slapos/recipe/zeo/__init__.py
index 8ac035f4dfa8f5291b854b9bffebce1741ebf7cd..184714f8d490b26d1bec3b72bb279ebba4ef3ed3 100644
--- a/slapos/recipe/zeo/__init__.py
+++ b/slapos/recipe/zeo/__init__.py
@@ -89,10 +89,9 @@ class Recipe(GenericBaseRecipe):
         self.substituteTemplate(template_filename, config))
 
     # Create running wrapper
-    wrapper_path = self.createPythonScript(
+    wrapper_path = self.createWrapper(
       self.options['wrapper-path'],
-      'slapos.recipe.librecipe.execute.generic_exec',
-      ((self.options['binary-path'].strip(),
-        '-C', self.options['conf-path']),))
+      (self.options['binary-path'].strip(),
+        '-C', self.options['conf-path']))
 
     return [configuration_path, wrapper_path]