diff --git a/docs/directives_template/rst.j2 b/docs/directives_template/rst.j2
--- a/docs/directives_template/rst.j2
+++ b/docs/directives_template/rst.j2
@@ -29,7 +29,7 @@
 
 .. raw:: html
 
-    <table border=1 cellpadding=4>
+    <table class="rawhtml" border=1 cellpadding=4>
     <tr>
     <th class="head">parameter</th>
     <th class="head">required</th>
@@ -41,12 +41,12 @@
     {% for k in option_keys %}
     {% set v = parameters[k] %}
     <tr>
-    <td>@{ k | html_ify }@</td>
+    <td class="bold">@{ k | html_ify | indent }@</td>
     <td>{% if v.get('required', False) %}yes{% else %}no{% endif %}</td>
-    <td>@{ v.description | html_ify | nl2br | indent }@{% if v['version_added'] %} (added in Taskotron @{v['version_added']}@){% endif %}</td>
-    <td>@{ v.type | html_ify }@</td>
-    <td>@{ v['default'] | html_ify }@</td>
-    <td><ul>{% for choice in v.get('choices',[]) -%}<li>@{ choice | html_ify }@</li>{% endfor -%}</ul></td>
+    <td>@{ v.description | html_ify | indent }@{% if v['version_added'] %} (added in Taskotron @{v['version_added']}@){% endif %}</td>
+    <td>@{ v.type | html_ify | indent }@</td>
+    <td>@{ v['default'] | html_ify | indent }@</td>
+    <td><ul>{% for choice in v.get('choices',[]) -%}<li>@{ choice | html_ify | indent }@</li>{% endfor -%}</ul></td>
     </tr>
     {% endfor %}
     </table>
diff --git a/docs/generate_directive_docs.py b/docs/generate_directive_docs.py
--- a/docs/generate_directive_docs.py
+++ b/docs/generate_directive_docs.py
@@ -30,6 +30,8 @@
 
 from jinja2 import Environment, FileSystemLoader
 
+from docutils.core import publish_parts
+
 # constants and paths
 
 # if a module is added in a version of Taskotron older than this, don't print
@@ -69,21 +71,17 @@
 
 
 def html_ify(text):
-    ''' convert symbols like I(this is in italics) to valid HTML '''
-
-    t = cgi.escape(str(text))
-    t = _ITALIC.sub("<em>" + r"\1" + "</em>", t)
-    t = _BOLD.sub("<b>" + r"\1" + "</b>", t)
-    t = _MODULE.sub("<span class='module'>" + r"\1" + "</span>", t)
-    t = _URL.sub("<a href='" + r"\1" + "'>" + r"\1" + "</a>", t)
-    t = _CONST.sub("<code>" + r"\1" + "</code>", t)
+    ''' convert rst to html '''
 
-    return t
+    out = publish_parts(str(text), writer_name="html")['body']
+    out = out.strip()
+    return out
 
 
 def nl2br(value):
+    ''' convert line feeds to <br/> '''
 
-    return value.replace('\n\n', '<br/>\n')
+    return value.replace('\n', '<br/>\n')
 
 
 def rst_fmt(text, fmt):
diff --git a/docs/source/_static/sane_directives_params_table.css b/docs/source/_static/sane_directives_params_table.css
new file mode 100644
--- /dev/null
+++ b/docs/source/_static/sane_directives_params_table.css
@@ -0,0 +1,29 @@
+table.rawhtml { 
+    border-collapse: collapse;
+}   
+
+table.rawhtml * tr {
+    border: 1px solid black;
+}   
+table.rawhtml * td, th {
+    border: 1px dotted grey;
+    padding: 5px;
+}   
+
+table.rawhtml * td {vertical-align: top;}
+
+table.rawhtml * th.head {
+    text-transform: capitalize;
+    font-style: italic;
+    font-weight: normal;
+}
+
+table.rawhtml * td.bold {font-weight: bold}
+
+table.rawhtml * ul {
+    padding: 0px;
+    padding-left: 1em;
+    margin: 0px;
+}   
+
+table.rawhtml * p {margin: 0; padding: 0}
diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html
new file mode 100644
--- /dev/null
+++ b/docs/source/_templates/layout.html
@@ -0,0 +1,5 @@
+{# layout.html #}
+{# Import the theme's layout. #}
+{% extends "!layout.html" %}
+
+{% set css_files = css_files + ['_static/sane_directives_params_table.css'] %}
diff --git a/libtaskotron/directives/__init__.py b/libtaskotron/directives/__init__.py
--- a/libtaskotron/directives/__init__.py
+++ b/libtaskotron/directives/__init__.py
@@ -24,9 +24,9 @@
 
 DOCUMENTATION = """
 # This is structured as a YAML document. If a key doesn't apply to your
-# directive, simply remove it. You can use reST markup in all string fields
-# unless noted otherwise. If you need to include `:` or newlines in a string,
-# start with with a `|` symbol and a newline, as shown below.
+# directive, simply remove it. You can use reST markup in all string fields.
+# If you need to include `:` or newlines in a string, start with with a `|`
+# symbol and a newline, as shown below.
 module: directive_name (same as the file name)
 short_description: one sentence describing the purpose of the directive
 description: |
@@ -44,12 +44,11 @@
 
   .. note:: This sentence will get highlighted and framed in a block.
 parameters:
-  # One or more options using the following format. You can't use any reST
-  # markup anywhere in this section, only plain text.
+  # One or more options using the following format.
   parameter_name:
     required: true
     description: |
-      Description of the option.
+      Description of the option, again with some ``values`` formatting.
 
       Blank lines force a line break.
     type: parameter type, e.g. `str` or `list of str`
diff --git a/libtaskotron/directives/bodhi_comment_directive.py b/libtaskotron/directives/bodhi_comment_directive.py
--- a/libtaskotron/directives/bodhi_comment_directive.py
+++ b/libtaskotron/directives/bodhi_comment_directive.py
@@ -27,14 +27,16 @@
     type: str
   doreport:
     required: true
-    description: Select `all` to always post the check result, regardless of
-      previoust Taskotron comments for the same update. Select `onchange` to
-      only post comments if the check result status changed (e.g. from `FAILED`
-      to `PASSED`), or if the `FAILED` status repeats itself *and* long enough
-      time has passed between these two failures (configurable as
-      `bodhi_posting_comments_span` in the config file). For production purposes
-      you usually want to use `onchange`, for development purposes you might
-      want to use `all`.
+    description: |
+      select ``all`` to always post the check result, regardless of
+      previoust Taskotron comments for the same update. Select ``onchange`` to
+      only post comments if the check result status changed (e.g. from ``FAILED``
+      to ``PASSED``), or if the ``FAILED`` status repeats itself **and** long
+      enough time has passed between these two failures (configurable as
+      ``bodhi_posting_comments_span`` in the config file).
+
+      For production purposes you usually want to use ``onchange``, for
+      development purposes you might want to use ``all``.
     type: str
     choice: [all, onchange]
 returns: |
diff --git a/libtaskotron/directives/bodhi_directive.py b/libtaskotron/directives/bodhi_directive.py
--- a/libtaskotron/directives/bodhi_directive.py
+++ b/libtaskotron/directives/bodhi_directive.py
@@ -17,28 +17,28 @@
   action:
     required: true
     description: specify action type. The only action available at the moment
-      is `download`.
+      is ``download``.
     type: str
   bodhi_id:
     required: true
     description: Bodhi update ID to download. This is usually in the form of
-      `FEDORA-2014-7485` or `pykickstart-1.99.42-1.fc20,anaconda-20.23-1.fc20`.
+      ``FEDORA-2014-7485`` or ``pykickstart-1.99.42-1.fc20,anaconda-20.23-1.fc20``.
     type: str
   arch:
     required: true
     description: |
       a list of architectures for which to download RPMs. In addition to
-      architectures supported by Taskotron by default, `src` is supported as
+      architectures supported by Taskotron by default, ``src`` is supported as
       well.
 
-      Note: `noarch` RPMs are always automatically downloaded even when not
-      requested, unless `src` is the only architecture requested.
+      Note: ``noarch`` RPMs are always automatically downloaded even when not
+      requested, unless ``src`` is the only architecture requested.
     type: list of str
 returns: |
   A dictionary containing following items:
 
-  * `downloaded_rpms`: (list of str) a list of local filenames of the downloaded
-    RPMs
+  * ``downloaded_rpms``: (list of str) a list of local filenames of the
+    downloaded RPMs
 raises: |
   * :class:`.TaskotronDirectiveError`: if no update with ``bodhi_id`` has been
     found
diff --git a/libtaskotron/directives/dummy_directive.py b/libtaskotron/directives/dummy_directive.py
--- a/libtaskotron/directives/dummy_directive.py
+++ b/libtaskotron/directives/dummy_directive.py
@@ -15,8 +15,8 @@
 parameters:
   result:
     required: true
-    description: arbitrary string. If it equals "FAIL" (case ignored), then the
-      directive raises an error.
+    description: arbitrary string. If it equals ``FAIL`` (case ignored), then
+      the directive raises an error.
     type: str
   msg:
     required: false
diff --git a/libtaskotron/directives/koji_directive.py b/libtaskotron/directives/koji_directive.py
--- a/libtaskotron/directives/koji_directive.py
+++ b/libtaskotron/directives/koji_directive.py
@@ -18,10 +18,10 @@
     description: |
       a list of architectures for which to download RPMs for the requested
       build/tag. In addition to architectures supported by Taskotron by default,
-      `src` is supported as well.
+      ``src`` is supported as well.
 
-      Note: `noarch` RPMs are always automatically downloaded even when not
-      requested, unless `src` is the only architecture requested.
+      Note: ``noarch`` RPMs are always automatically downloaded even when not
+      requested, unless ``src`` is the only architecture requested.
     type: list of str
     choices: [standard Taskotron architectures, src]
   command:
@@ -34,13 +34,13 @@
     required: true
     description: |
       N(E)VR of a Koji build to download. Only required when
-      `command="download"`. Example: `xchat-2.8.8-21.fc20`
+      ``command="download"``. Example: ``xchat-2.8.8-21.fc20``
     type: str
   koji_tag:
     required: true
     description: |
       name of a Koji tag to download all builds from. Only required when
-      `command="download_tag"`. Example: `f20-updates-pending`
+      ``command="download_tag"``. Example: ``f20-updates-pending``
     type: str
   target_dir:
     required: false
diff --git a/libtaskotron/directives/python_directive.py b/libtaskotron/directives/python_directive.py
--- a/libtaskotron/directives/python_directive.py
+++ b/libtaskotron/directives/python_directive.py
@@ -20,13 +20,13 @@
   callable:
     required: true
     description: name of the object to call. This can be a function reference,
-      a callable instance reference, or an `instance.method` reference. See
+      a callable instance reference, or an ``instance.method`` reference. See
       examples.
     type: str
   <kwarg>:
     required: false
-    description: arbitrarily named parameter with a value. All these `key=value`
-      pairs will be passed to the python script as `callable` parameters.
+    description: arbitrarily named parameter with a value. All these ``key=value``
+      pairs will be passed to the python script as ``callable`` parameters.
     type: anything
 returns: |
   The output of the python script, which must be either ``None`` or a
diff --git a/libtaskotron/directives/yumrepoinfo_directive.py b/libtaskotron/directives/yumrepoinfo_directive.py
--- a/libtaskotron/directives/yumrepoinfo_directive.py
+++ b/libtaskotron/directives/yumrepoinfo_directive.py
@@ -15,17 +15,17 @@
   koji_tag:
     required: true
     description: |
-      name of the Koji tag, e.g. `f20`, `f20-updates`, `f20-updates-testing`,
-      or `rawhide`.
+      name of the Koji tag, e.g. ``f20``, ``f20-updates``,
+      ``f20-updates-testing``, or ``rawhide``.
 
-      If the tag ends with `-pending` suffix, this suffix is stripped (because
+      If the tag ends with ``-pending`` suffix, this suffix is stripped (because
       pending tags are not real repositories), and the resulting tag is used.
     type: str
   arch:
     required: true
     description: list of architectures. In this list, all "meta architectures"
-      like `all`, `src` and `noarch` are ignored, and only a single "real
-      architecture" is expected there (e.g. `x86_64` or `i386`).
+      like ``all``, ``src`` and ``noarch`` are ignored, and only a single "real
+      architecture" is expected there (e.g. ``x86_64`` or ``i386``).
     type: list of str
 returns: |
     A dictionary. One of the keys is ``koji_tag`` and URL for the respective

