diff --git a/actions/pm-build-model b/actions/pm-build-model
index 6992028b2156bb8caa424fd52ecbfa50614f2807..daafa09c30934bfcac3d48b40117056201fa327c 100755
--- a/actions/pm-build-model
+++ b/actions/pm-build-model
@@ -1,89 +1,77 @@
-import os, argparse
-import ost
-from ost import io, settings
-from ost.bindings import dssp
-from promod3 import modelling
-from promod3.core import helper
+'''
+Automatically build a model from alignments and template structures.
 
-### CHANGELOG - START
-# 2016-03-02 - created
-### CHANGELOG - END
+Example usage:
+  pm build-model -f aln.fasta -p tpl.pdb
+    This reads a target-template alignment from aln.fasta and a matching
+    structure from tpl.pdb and produces a gap-less model which is stored
+    as model.pdb.
 
-### EXIT STATUS - START
-# 1 - template structure file does not exist
-# 2 - template structure file has unsupported file extension
-# 3 - alignment file does not exist
-# 4 - alignment file has unsupported file extension
-# 5 - failed to perform modelling (internal error)
-# 6 - failed to write results to file
-### EXIT STATUS - END
+Please see the ProMod3 documentation for details on more advanced usage.
 
-### SETUP - START
-DESCRIPTION = '''\
-Automatically build a model from an alignment and a template structure.
+Possible exit codes:
+  0: all went well
+  1: an unhandled exception was raised
+  2: arguments cannot be parsed or required arguments are missing
+  3: failed to perform modelling (internal error)
+  4: failed to write results to file
+  other non-zero: failure in argument checking (see doc. PM3ArgumentParser)
 '''
-### SETUP - END
 
-### FUNCTIONS - START
-def _ParserArgs():
-    p = argparse.ArgumentParser(prog="pm build-model", description=DESCRIPTION,
-                        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-    p.add_argument('template_file', metavar='<TEMPLATE STRUCTURE>', type=str,
-                   help='File providing coordinates, either PDB or mmCIF '
-                       +'format, plain or gzipped.')
-    p.add_argument('alignment_file', metavar='<ALIGNMENT>', type=str,
-                   help='File providing the target-template alignment')
-    p.add_argument('-o', '--model-file', metavar='<FILENAME>', type=str,
-                   help='File to store model coordinates.', default='model.pdb')
-    opts = p.parse_args()
+import os
+import ost
+from ost import io, settings
+from ost.bindings import dssp
+from promod3 import modelling
+from promod3.core import pm3argparse, helper
+
+# make sure we see output when passing '-h'
+ost.PushVerbosityLevel(2)
 
-    # check arguments
-    helper.FileExists('Template structure', 1, opts.template_file)
-    helper.FileExtension('Template structure', 2, opts.template_file,
-                         ('pdb', 'cif'), gzip=True)
-    helper.FileExists('Alignment', 3, opts.alignment_file)
-    helper.FileExtension('Alignment', 4, opts.alignment_file, ('fasta', 'fas'),
-                         gzip=False)
-    return opts
-### FUNCTIONS - END
+# parse command line
+parser = pm3argparse.PM3ArgumentParser(__doc__, action=True)
+parser.AddAlignment()
+parser.AddStructure(attach_views=True)
+parser.AssembleParser()
+parser.add_argument('-o', '--model-file', metavar='<FILENAME>', type=str,
+                    default='model.pdb', help='File to store model coordinates'+
+                                              ' (default: %(default)s).')
+# lots of checking being done here -> see PM3ArgumentParser
+opts = parser.Parse()
 
-### MAIN - START
-opts = _ParserArgs()
+# report alignments and add dssp
+ost.PushVerbosityLevel(3)
+if len(opts.alignments) == 1:
+    ost.LogInfo("Build model with the following alignment:")
+elif len(opts.alignments) > 1:
+    ost.LogInfo("Build " + str(len(opts.alignments)) + " models with the "+
+                "following alignments:")
+dssp_usable = True
+for aln in opts.alignments:
+    ost.LogInfo(aln.ToString(80))
+    if dssp_usable:
+        for i in range(1, aln.GetCount()):
+            try:
+                dssp.AssignDSSP(aln.GetSequence(i).GetAttachedView())
+            except settings.FileNotFound:
+                dssp_usable = False
+                break
+if not dssp_usable:
+    ost.LogInfo("dssp binary is missing. You can get better modelling results "+
+                "if you install dssp.")
 
-# load template structure
-tpl = io.LoadEntity(opts.template_file)
-# load target-template alignment
-aln = io.LoadAlignment(opts.alignment_file)
-# TODO: check that alignment sequences are in template
-# try to add sec. structure
-try:
-    dssp.AssignDSSP(tpl)
-except settings.FileNotFound:
-    print "dssp binary is missing. You can get better modelling results if " +\
-          "you install dssp."
+# model it
 try:
-    ost.PushVerbosityLevel(3)
-    ost.LogInfo("Build model with following alignment:")
-    ost.LogInfo(aln.ToString(80))
     # get raw model
-    aln.AttachView(1, tpl.CreateFullView())
-    mhandle = modelling.BuildRawModel(aln)
+    mhandle = modelling.BuildRawModel(opts.alignments)
     # build final model
     final_model = modelling.BuildFromRawModel(mhandle)
-    ost.PopVerbosityLevel()
 except Exception as ex:
-    err_tpl = "An exception of type {0} occured. Arguments:\n{1!r}"
-    message = err_tpl.format(type(ex).__name__, ex.args)
-    helper.MsgErrorAndExit("Modelling failed!\n" + message, 5)
+    helper.MsgErrorAndExit("Failed to perform modelling! An exception of type "+
+                           type(ex).__name__ + " occured: " + str(ex), 3)
+
+# output
+ost.PopVerbosityLevel()
 io.SavePDB(final_model, opts.model_file)
 if not os.path.isfile(opts.model_file):
-    helper.MsgErrorAndExit("Failed to write model file '%s'." % opts.model_file, 6)
-### MAIN - END
-
-
-# NOTE: this follows build-rawmodel
-# -> interface, error checks and code may change to:
-#    - follow pm-help
-#    - use pm3argparse to get inputs
-#    - check that we have desired alignments in file
-#    - multi-template??? :o
\ No newline at end of file
+    helper.MsgErrorAndExit("Failed to write model file '%s'." % opts.model_file, 4)
diff --git a/actions/pm-build-rawmodel b/actions/pm-build-rawmodel
index d527254df7270d5bee2b7b0dce828db27e569d8c..2efc3c4fbe4de151c48d85e8a8b60864ca479268 100755
--- a/actions/pm-build-rawmodel
+++ b/actions/pm-build-rawmodel
@@ -1,90 +1,55 @@
-import os, argparse
-from ost import io
-from promod3 import modelling
-from promod3.core import helper
-
-### CHANGELOG - START
-# 2013-11-07 - created
-### CHANGELOG - END
-
-### EXIT STATUS - START
-# 1 - template structure file does not exist
-# 2 - template structure file has unsupported file extension
-# 3 - alignment file does not exist
-# 4 - alignment file has unsupported file extension
-# 5 - failed to write results to file
-### EXIT STATUS - END
-
-### SETUP - START
-DESCRIPTION = '''\
-Create a very basic raw model from an alignment and a template structure.
+'''
+Create a very basic raw model from alignments and template structures.
 Conserved parts are copied from the template and an incomplete pdb file is
 generated.
-'''
-### SETUP - END
-
-### FUNCTIONS - START
-def _ParserArgs():
-    p = argparse.ArgumentParser(prog="pm build-rawmodel", description=DESCRIPTION,
-                        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-    p.add_argument('template_file', metavar='<TEMPLATE STRUCTURE>', type=str,
-                   help='File providing coordinates, either PDB or mmCIF '
-                       +'format, plain or gzipped.')
-    p.add_argument('alignment_file', metavar='<ALIGNMENT>', type=str,
-                   help='File providing the target-template alignment')
-    p.add_argument('-o', '--model-file', metavar='<FILENAME>', type=str,
-                   help='File to store model coordinates.', default='model.pdb')
-    opts = p.parse_args()
-
-    # check arguments
-    helper.FileExists('Template structure', 1, opts.template_file)
-    helper.FileExtension('Template structure', 2, opts.template_file,
-                         ('pdb', 'cif'), gzip=True)
-    helper.FileExists('Alignment', 3, opts.alignment_file)
-    helper.FileExtension('Alignment', 4, opts.alignment_file, ('fasta', 'fas'),
-                         gzip=False)
-    return opts
-### FUNCTIONS - END
 
-### MAIN - START
-opts = _ParserArgs()
-
-# load template structure
-tpl = io.LoadEntity(opts.template_file)
-# load target-template alignment
-aln = io.LoadAlignment(opts.alignment_file)
-# check that alignment sequences are in template
-# mark target and template sequence in alignment
-# auto-mode: chains in alignment are marked as sep.A, sep.B, etc.
-# how can we do multi-whatever things?
+Example usage:
+  pm build-rawmodel -f aln.fasta -p tpl.pdb
+    This reads a target-template alignment from aln.fasta and a matching
+    structure from tpl.pdb and produces a raw model which is stored as
+    model.pdb.
+
+Please see the ProMod3 documentation for details on more advanced usage.
+
+Possible exit codes:
+  0: all went well
+  1: an unhandled exception was raised
+  2: arguments cannot be parsed or required arguments are missing
+  3: failed to generate raw model (internal error)
+  4: failed to write results to file
+  other non-zero: failure in argument checking (see doc. PM3ArgumentParser)
+'''
 
-aln.AttachView(1, tpl.CreateFullView())
-result = modelling.BuildRawModel(aln)
-io.SavePDB(result.model, opts.model_file)
+import os
+import ost
+from ost import io
+from promod3 import modelling
+from promod3.core import pm3argparse, helper
+
+# make sure we see output when passing '-h'
+ost.PushVerbosityLevel(2)
+
+# parse command line
+parser = pm3argparse.PM3ArgumentParser(__doc__, action=True)
+parser.AddAlignment()
+parser.AddStructure(attach_views=True)
+parser.AssembleParser()
+parser.add_argument('-o', '--model-file', metavar='<FILENAME>', type=str,
+                    default='model.pdb', help='File to store model coordinates'+
+                                              ' (default: %(default)s).')
+# lots of checking being done here -> see PM3ArgumentParser
+opts = parser.Parse()
+
+# get raw model
+try:
+    mhandle = modelling.BuildRawModel(opts.alignments)
+except Exception as ex:
+    helper.MsgErrorAndExit("Failed to generate raw model! An exception of "+
+                           "type " + type(ex).__name__ + " occured: " + str(ex),
+                           3)
+
+# output
+ost.PopVerbosityLevel()
+io.SavePDB(mhandle.model, opts.model_file)
 if not os.path.isfile(opts.model_file):
-    helper.MsgErrorAndExit("Failed to write model file '%s'." % opts.model_file, 5)
-### MAIN - END
-
-
-
-# parse args
-#  - we need an input alignment
-#  - only 2 seqs allowed, option switch to mark which one is target
-#  - what happens on arbitrary sequences? One has to correspond with the
-#    template structure
-#  - what happens for a alignment list?
-#  - option for name model file
-#  - default does not overwrite, but add switch to do so
-#  - switch to turn of reporting gaps
-#  - option to go calpha only
-# prepare stuff
-# build model
-# store stuff
-# return stuff?
-# report gaps?
-# documentation!
-
-## Emacs magic
-# Local Variables:
-# mode: python
-# End:
+    helper.MsgErrorAndExit("Failed to write model file '%s'." % opts.model_file, 4)
diff --git a/actions/tests/test_action_build-model.py b/actions/tests/test_action_build-model.py
index a6ec7407dbf10172fb7e4b4070f2c19a1384ce5a..a0889fd0c048c720c04d8ec7d4c07fba01f22047 100644
--- a/actions/tests/test_action_build-model.py
+++ b/actions/tests/test_action_build-model.py
@@ -23,9 +23,10 @@ class HelpActionTests(test_actions.ActionTestCase):
         # test with proper inputs (and check resulting file)
         pdbpath = os.path.join('data', 'gly.pdb')
         faspath = os.path.join('data', 'seq_ins.fasta')
-        self.RunExitStatusTest(0, [pdbpath, faspath])
+        my_args = ['-p', pdbpath, '-f', faspath]
+        self.RunExitStatusTest(0, my_args)
         io.LoadPDB('model.pdb')
-        self.RunExitStatusTest(0, ['-o mymodel.pdb', pdbpath, faspath])
+        self.RunExitStatusTest(0, my_args + ['-o', 'mymodel.pdb'])
         io.LoadPDB('mymodel.pdb')
         # clean up this test
         os.remove('model.pdb')
@@ -35,20 +36,14 @@ class HelpActionTests(test_actions.ActionTestCase):
         # test error codes
         pdbpath = os.path.join('data', 'gly.pdb')
         faspath = os.path.join('data', 'seq.fasta')
-        # 1 - template structure file does not exist
-        self.RunExitStatusTest(1, ['dummy.pdb', faspath])
-        # 2 - template structure file has unsupported file extension
-        self.RunExitStatusTest(2, [faspath, faspath])
-        # 3 - alignment file does not exist
-        self.RunExitStatusTest(3, [pdbpath, 'dummy.fasta'])
-        # 4 - alignment file has unsupported file extension
-        self.RunExitStatusTest(4, [pdbpath, pdbpath])
-        # 5 - failed to perform modelling (internal error)
+        my_args = ['-p', pdbpath, '-f', faspath]
+        # 2 - wrong input (most of this tested in pm3argparse!)
+        self.RunExitStatusTest(2, ['-p', pdbpath])
+        # 3 - failed to perform modelling (internal error)
         # -> we cannot really test this one...
-        # 6 - failed to write results to file
+        # 4 - failed to write results to file
         failpath = os.path.join('cannotpossiblyexist', 'whatever.pdb')
-        self.RunExitStatusTest(6, ['-o '+failpath, pdbpath, faspath])
-
+        self.RunExitStatusTest(4, ['-o', failpath] + my_args)
 
 if __name__ == "__main__":
     from ost import testutils
diff --git a/actions/tests/test_action_build-rawmodel.py b/actions/tests/test_action_build-rawmodel.py
index 4c920610cedb043ca1be46627bbc722b221ddfa2..3f222c62a0644597920c1d7654764deb2e94a818 100644
--- a/actions/tests/test_action_build-rawmodel.py
+++ b/actions/tests/test_action_build-rawmodel.py
@@ -23,9 +23,10 @@ class HelpActionTests(test_actions.ActionTestCase):
         # test with proper inputs (and check resulting file)
         pdbpath = os.path.join('data', 'gly.pdb')
         faspath = os.path.join('data', 'seq.fasta')
-        self.RunExitStatusTest(0, [pdbpath, faspath])
+        my_args = ['-p', pdbpath, '-f', faspath]
+        self.RunExitStatusTest(0, my_args)
         io.LoadPDB('model.pdb')
-        self.RunExitStatusTest(0, ['-o mymodel.pdb', pdbpath, faspath])
+        self.RunExitStatusTest(0, my_args + ['-o', 'mymodel.pdb'])
         io.LoadPDB('mymodel.pdb')
         # clean up this test
         os.remove('model.pdb')
@@ -35,18 +36,14 @@ class HelpActionTests(test_actions.ActionTestCase):
         # test error codes
         pdbpath = os.path.join('data', 'gly.pdb')
         faspath = os.path.join('data', 'seq.fasta')
-        # 1 - template structure file does not exist
-        self.RunExitStatusTest(1, ['dummy.pdb', faspath])
-        # 2 - template structure file has unsupported file extension
-        self.RunExitStatusTest(2, [faspath, faspath])
-        # 3 - alignment file does not exist
-        self.RunExitStatusTest(3, [pdbpath, 'dummy.fasta'])
-        # 4 - alignment file has unsupported file extension
-        self.RunExitStatusTest(4, [pdbpath, pdbpath])
-        # 5 - failed to write results to file
+        my_args = ['-p', pdbpath, '-f', faspath]
+        # 2 - wrong input (most of this tested in pm3argparse!)
+        self.RunExitStatusTest(2, ['-p', pdbpath])
+        # 3 - failed to generate raw model (internal error)
+        # -> we cannot really test this one...
+        # 4 - failed to write results to file
         failpath = os.path.join('cannotpossiblyexist', 'whatever.pdb')
-        self.RunExitStatusTest(5, ['-o '+failpath, pdbpath, faspath])
-
+        self.RunExitStatusTest(4, ['-o', failpath] + my_args)
 
 if __name__ == "__main__":
     from ost import testutils
diff --git a/core/pymod/core/pm3argparse.py b/core/pymod/core/pm3argparse.py
index 7ad9e341a3d63f9cf1081e305f33266b50d11f66..de9a6320da9c9acdd521fcde6f2bf2798e6dcf65 100644
--- a/core/pymod/core/pm3argparse.py
+++ b/core/pymod/core/pm3argparse.py
@@ -343,7 +343,7 @@ class PM3ArgumentParser(argparse.ArgumentParser):
         argparse.ArgumentParser.__init__(self, prog=prog,
                                          description=description,
                                          formatter_class=\
-                                         argparse.ArgumentDefaultsHelpFormatter)
+                                         argparse.RawDescriptionHelpFormatter)
         self.action = action
         self.activate = set()
 
diff --git a/core/tests/test_pm3argparse.py b/core/tests/test_pm3argparse.py
index daa54464ded1f2278888933862b76a13f9d4d1db..f7e9ff7bce47a59a17d5bd68220c4cf5e6e041c6 100644
--- a/core/tests/test_pm3argparse.py
+++ b/core/tests/test_pm3argparse.py
@@ -951,13 +951,14 @@ class PM3ArgParseTests(unittest.TestCase):
     def checkView(self, alns):
         # helper: checks if all alignments have attached views for templates
         for aln in alns:
-            self.assertTrue(aln.GetSequence(1).HasAttachedView())
-            for col in aln:
-                res = col.GetResidue(1)
-                all_good = (res.IsValid() and res.one_letter_code == col[1])\
-                           or (not res.IsValid() and '-' == col[1])
-                mymsg = "mismatch col. " + str(col) + " with res. " + str(res)
-                self.assertTrue(all_good, msg=mymsg)
+            for i in range(1, aln.GetCount()):
+                self.assertTrue(aln.GetSequence(i).HasAttachedView())
+                for col in aln:
+                    res = col.GetResidue(i)
+                    all_good = (res.IsValid() and res.one_letter_code == col[i])\
+                               or (not res.IsValid() and '-' == col[i])
+                    mymsg = "mismatch col. " + str(col) + " with res. " + str(res)
+                    self.assertTrue(all_good, msg=mymsg)
 
     def testAttachView(self):
         parser = pm3argparse.PM3ArgumentParser(__doc__, action=False)
diff --git a/doc/tests/test_doctests.py b/doc/tests/test_doctests.py
index 369b64fc4c53b905be17ab6741a4be73d0948ec8..f6cdb7c31fda6f10f7cc04b9a376dba40b55d1c6 100644
--- a/doc/tests/test_doctests.py
+++ b/doc/tests/test_doctests.py
@@ -132,9 +132,9 @@ class DocTests(unittest.TestCase):
         out_lines = serr.splitlines()
         self.assertRegexpMatches(out_lines[0], "usage: .*")
         self.assertEqual(out_lines[2].strip(),
-                         "Place the description of your script right in the file and import it via")
+                         "Place the description of your script right in the file and import")
         self.assertEqual(out_lines[3].strip(),
-                         "'__doc__' as description to the parser ('-h', '--help').")
+                         "it via '__doc__' as description to the parser ('-h', '--help').")
         self.assertEqual(out_lines[5].strip(), "optional arguments:")
         self.assertGreater(len(out_lines), 5)