diff --git a/src/execo_engine/utils.py b/src/execo_engine/utils.py
index 8d055872887f38f1ee82302e7fe0d41b3cf95014..0082fe9c6325808bd64fdf27f17144a23d016fbe 100644
--- a/src/execo_engine/utils.py
+++ b/src/execo_engine/utils.py
@@ -17,7 +17,7 @@
 # along with Execo.  If not, see <http://www.gnu.org/licenses/>
 
 from execo.utils import MAXFD
-import os, unicodedata, re, sys, ctypes, signal
+import os, unicodedata, re, sys, ctypes, signal, pty
 
 def _redirect_fd(fileno, filename):
     # create and open file filename, and redirect open file fileno to it
@@ -45,9 +45,12 @@ def _disable_sigs(sigs):
     SIG_BLOCK = 0
     libc.sigprocmask(SIG_BLOCK, ctypes.pointer(mask), 0)
 
-def _tee_fd(fileno, filename):
+def _tee_fd(fileno, filename, use_pty):
     # create and open file filename, and duplicate open file fileno to it
-    pr, pw = os.pipe()
+    if use_pty:
+        pr, pw = pty.openpty()
+    else:
+        pr, pw = os.pipe()
     pid = os.fork()
     if pid == 0:
         os.dup2(pr, 0)
@@ -78,12 +81,12 @@ def redirect_outputs(stdout_filename, stderr_filename):
     # and 0 as the buffer size (unbuffered)
     sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1 if sys.version_info >= (3,) else 0)
 
-def copy_outputs(stdout_filename, stderr_filename):
+def copy_outputs(stdout_filename, stderr_filename, use_pty=False):
     """Copy, and optionnaly merge, stdout and stderr to file(s)"""
     sys.stdout.flush()
     sys.stderr.flush()
-    _tee_fd(1, stdout_filename)
-    _tee_fd(2, stderr_filename)
+    _tee_fd(1, stdout_filename, use_pty)
+    _tee_fd(2, stderr_filename, use_pty)
     # additionnaly force stdout unbuffered by reopening stdout
     # file descriptor with write mode
     # and 0 as the buffer size (unbuffered)