docs: def start_pipeline(self, args=None, multi=False):
          """
          Initialize setup. Do some setup, like tee output, print some diagnostics, create temp files.
          You provide only the output directory (used for pipeline stats, log, and status flag files).
          """
          # Perhaps this could all just be put into __init__, but I just kind of like the idea of a start function
          self.make_sure_path_exists(self.outfolder)
  
          # By default, Pypiper will mirror every operation so it is displayed both
          # on sys.stdout **and** to a log file. Unfortunately, interactive python sessions
          # ruin this by interfering with stdout. So, for interactive mode, we do not enable 
          # the tee subprocess, sending all output to screen only.
          # Starting multiple PipelineManagers in the same script has the same problem, and
          # must therefore be run in interactive_mode.
  
          interactive_mode = multi or not hasattr(__main__, "__file__")
          if interactive_mode:
              print("Warning: You're running an interactive python session. "
                    "This works, but pypiper cannot tee the output, so results "
                    "are only logged to screen.")
          else:
              sys.stdout = Unbuffered(sys.stdout)
              # sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)  # Unbuffer output
  
              # The tee subprocess must be instructed to ignore TERM and INT signals;
              # Instead, I will clean up this process in the signal handler functions.
              # This is required because otherwise, if pypiper receives a TERM or INT,
              # the tee will be automatically terminated by python before I have a chance to
              # print some final output (for example, about when the process stopped),
              # and so those things don't end up in the log files because the tee
              # subprocess is dead. Instead, I will handle the killing of the tee process
              # manually (in the exit handler).
  
              # a for append to file
              
              tee = subprocess.Popen(
                  ["tee", "-a", self.pipeline_log_file], stdin=subprocess.PIPE,
                  preexec_fn=self._ignore_interrupts)
  
              # If the pipeline is terminated with SIGTERM/SIGINT,
              # make sure we kill this spawned tee subprocess as well.
              # atexit.register(self._kill_child_process, tee.pid, proc_name="tee")
              os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
              os.dup2(tee.stdin.fileno(), sys.stderr.fileno())
  
              self.tee = tee
  
          # For some reason, this exit handler function MUST be registered after
          # the one that kills the tee process.
          atexit.register(self._exit_handler)
  
          # A future possibility to avoid this tee, is to use a Tee class; this works for anything printed here
          # by pypiper, but can't tee the subprocess output. For this, it would require using threading to
          # simultaneously capture and display subprocess output. I shelve this for now and stick with the tee option.
          # sys.stdout = Tee(self.pipeline_log_file)
  
          # Record the git version of the pipeline and pypiper used. This gets (if it is in a git repo):
          # dir: the directory where the code is stored
          # hash: the commit id of the last commit in this repo
          # date: the date of the last commit in this repo
          # diff: a summary of any differences in the current (run) version vs. the committed version
  
          # Wrapped in try blocks so that the code will not fail if the pipeline or pypiper are not git repositories
          gitvars = {}
          try:
              # pypiper dir
              ppd = os.path.dirname(os.path.realpath(__file__))
              gitvars['pypiper_dir'] = ppd
              gitvars['pypiper_hash'] = subprocess.check_output("cd " + ppd + "; git rev-parse --verify HEAD 2>/dev/null", shell=True)
              gitvars['pypiper_date'] = subprocess.check_output("cd " + ppd + "; git show -s --format=%ai HEAD 2>/dev/null", shell=True)
              gitvars['pypiper_diff'] = subprocess.check_output("cd " + ppd + "; git diff --shortstat HEAD 2>/dev/null", shell=True)
              gitvars['pypiper_branch'] = subprocess.check_output("cd " + ppd + "; git branch | grep '*' 2>/dev/null", shell=True)
          except Exception:
              pass
          try:
              # pipeline dir
              pld = os.path.dirname(os.path.realpath(sys.argv[0]))
              gitvars['pipe_dir'] = pld
              gitvars['pipe_hash'] = subprocess.check_output("cd " + pld + "; git rev-parse --verify HEAD 2>/dev/null", shell=True)
              gitvars['pipe_date'] = subprocess.check_output("cd " + pld + "; git show -s --format=%ai HEAD 2>/dev/null", shell=True)
              gitvars['pipe_diff'] = subprocess.check_output("cd " + pld + "; git diff --shortstat HEAD 2>/dev/null", shell=True)
              gitvars['pipe_branch'] = subprocess.check_output("cd " + pld + "; git branch | grep '*' 2>/dev/null", shell=True)
          except Exception:
              pass
          
          # Print out a header section in the pipeline log:
          # Wrap things in backticks to prevent markdown from interpreting underscores as emphasis.
          # print("----------------------------------------")
          print("### [Pipeline run code and environment:]\n")
          print("* " + "Command".rjust(20) + ":  " + "`" + str(" ".join(sys.argv)) + "`")
          print("* " + "Compute host".rjust(20) + ":  " + platform.node())
          print("* " + "Working dir".rjust(20) + ":  " + os.getcwd())
          print("* " + "Outfolder".rjust(20) + ":  " + self.outfolder)
  
          self.timestamp("* " + "Pipeline started at".rjust(20) + ":  ")
  
          print("\n### [Version log:]\n")
          print("* " + "Python version".rjust(20) + ":  " + platform.python_version())
          try:
              print("* " + "Pypiper dir".rjust(20) + ":  " + "`" + gitvars['pypiper_dir'].strip() + "`")
              print("* " + "Pypiper version".rjust(20) + ":  " + __version__)
              print("* " + "Pypiper hash".rjust(20) + ":  " + str(gitvars['pypiper_hash']).strip())
              print("* " + "Pypiper branch".rjust(20) + ":  " + str(gitvars['pypiper_branch']).strip())
              print("* " + "Pypiper date".rjust(20) + ":  " + str(gitvars['pypiper_date']).strip())
              if "" != str(gitvars['pypiper_diff']):
                  print("* " + "Pypiper diff".rjust(20) + ":  " + str(gitvars['pypiper_diff']).strip())
          except KeyError:
              # It is ok if keys aren't set, it means pypiper isn't in a  git repo.
              pass
  
          try:
              print("* " + "Pipeline dir".rjust(20) + ":  " + "`" + gitvars['pipe_dir'].strip() + "`")
              print("* " + "Pipeline version".rjust(20) + ":  " + str(self.pl_version))
              print("* " + "Pipeline hash".rjust(20) + ":  " + str(gitvars['pipe_hash']).strip())
              print("* " + "Pipeline branch".rjust(20) + ":  " + str(gitvars['pipe_branch']).strip())
              print("* " + "Pipeline date".rjust(20) + ":  " + str(gitvars['pipe_date']).strip())
              if (gitvars['pipe_diff'] != ""):
                  print("* " + "Pipeline diff".rjust(20) + ":  " + str(gitvars['pipe_diff']).strip())
          except KeyError:
              # It is ok if keys aren't set, it means the pipeline isn't a git repo.
              pass
  
          # Print all arguments (if any)
          print("\n### [Arguments passed to pipeline:]\n")
          for arg, val in (vars(args) if args else dict()).items():
              argtext = "`{}`".format(arg)
              valtext = "`{}`".format(val)
              print("* {}:  {}".format(argtext.rjust(20), valtext))
          print("\n----------------------------------------\n")
          self._set_status_flag(RUN_FLAG)
  
          # Record the start in PIPE_profile and PIPE_commands output files so we
          # can trace which run they belong to
  
          with open(self.pipeline_commands_file, "a") as myfile:
              myfile.write("# Pipeline started at " + time.strftime("%m-%d %H:%M:%S", time.localtime(self.starttime)) + "\n\n")
  
          with open(self.pipeline_profile_file, "a") as myfile:
              myfile.write("# Pipeline started at " + time.strftime("%m-%d %H:%M:%S", time.localtime(self.starttime)) + "\n\n")